Я хочу иметь возможность использовать std::optional<int>
с Boost.Format.
#include <iostream>
#include <optional>
#include <boost/format.hpp>
struct SomeType
{
int x;
};
std::ostream& operator<<(std::ostream& os, const SomeType& t)
{
os << t.x;
return os;
}
std::ostream& operator<<(std::ostream& os, const std::optional<int>& t)
{
os << t.value_or(0);
return os;
}
void test()
{
SomeType t{42};
std::cout << (boost::format("%s") % t); //this is fine
std::optional<int> i = 42;
std::cout << (boost::format("%s") % i); //nope
}
Приведенный выше код дает мне следующую ошибку компилятора:
opt/compiler-explorer/libs/boost_1_68_0/boost/format/feed_args.hpp:99:12: error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'const std::optional<int>')
os << x ;
~~~^~~~
Там нет ошибок компилятора, если я просто пройти i
прямо к std::cout
,
boost::format("%s") % i
вызывает вызов operator<<
, Во время компиляции соблюдается правило поиска имени, чтобы найти operator<<
,
За boost::format("%s") % t
обе структуры SomeType
а также std::ostream& operator<<(std::ostream& os, const SomeType& t)
определяется в глобальном пространстве имен, используя ADL, operator<<
найден.
За (boost::format("%s") % i)
, std::optional
определяется в пространстве имен std
, но соответствующий operator<<
определяется в глобальном пространстве имен. Используя ADL, boost не сможет его найти. А также
поиск без ADL проверяет объявления функций с внешними связями, которые видны из контекста определения шаблона,
поэтому компилятор не может найти operator<<
который вы определили.
Обходной путь: wrap std :: необязательный внутри вашего собственного ReferenceWrapper, затем определите вставщик для вашей оболочки в том же пространстве имен, где определен ReferenceWrapper.
Других решений пока нет …