是什么阻止了我的流运算符重载可选int的Boost.Format表单?

时间:2018-11-26 08:32:11

标签: c++ boost boost-format

我希望能够将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,就不会有编译器错误。

1 个答案:

答案 0 :(得分:2)

boost::format("%s") % i调用对operator<<的调用。在查找operator<<时会遵循名称查找规则。

对于boost::format("%s") % t,通过使用ADL在全局命名空间中定义了结构SomeTypestd::ostream& operator<<(std::ostream& os, const SomeType& t),找到了operator<<

对于(boost::format("%s") % i)std::optional是在命名空间std中定义的,而相应的operator<<是在全局命名空间中定义的。通过使用ADL,boost将无法找到它。还有

  

非ADL查找会检查具有外部链接的函数声明,这些声明在模板定义上下文中可见

因此编译器无法找到您定义的operator<<

一种解决方法:将std :: optional包装在您自己的ReferenceWrapper中,然后在定义了ReferenceWrapper的同一命名空间中为包装器定义插入器。