我想测试一下如下的简单内容:
#include <iostream>
#include <boost/variant.hpp>
template<typename T1,typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1,T2>& dt){
os << dt.first << dt.second;
return os;
}
int main(){
boost::variant<int, std::pair<int,int>, bool> v;
v = std::pair<int,int>(3,3);
std::cout << v << std::endl;
}
这实际上应该有效,因为对于普通类型,例如int, double
等,它会编译。
boost::variant
有一个打印机vistor,它在内部使用它将内容输出到流。
实际上这无法编译,但我真的不知道这个问题:
此处的代码失败:在variant_io.hpp
中template <typename OStream>
class printer
: public boost::static_visitor<>
{
private: // representation
OStream& out_;
public: // structors
explicit printer(OStream& out)
: out_( out )
{
}
public: // visitor interface
template <typename T>
void operator()(const T& operand) const
{
out_ << operand; // HEEEEEEERRRRREE!!!!!!!!!!!!
}
private:
printer& operator=(const printer&);
};
收到消息:
/usr/local/include/boost/variant/detail/variant_io.hpp|64|error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&'
有人知道我做错了什么,为什么?
非常感谢!
答案 0 :(得分:5)
很可能它没有找到你operator <<
的超载,然后在尝试匹配其他超载时感到困惑,导致你得到的任何消息。
你做错了什么:你在全局命名空间中重载了流操作符而不是在右边的类中定义的命名空间,因此ADL找不到它。
不幸的是,试图为标准类重载流操作符是一个注定要失败的练习。你实际上无法做到这一点。我不确定是否有针对它的明确规则。但是,如果您将操作符放在命名空间std
中,以便ADL可以正确查找它,则违反了您无法将自己的内容添加到命名空间std
的规则除非在非常具体的情况下,这不是其中之一。
底线是std::pair
没有流操作符,并且无法合法添加有用的通用操作符。如果其中一个参数是您自己定义的类,则可以为特定实例添加一个;在这种情况下,操作员需要放在您自己的班级旁边。
答案 1 :(得分:3)
必须通过参数依赖查找找到重载的operator<<
。这意味着你必须将它放在其中一个参数的关联命名空间中。
第一个参数只有一个关联的命名空间std
。第二个也只有一个关联的命名空间std
。但是,只允许在std
中为用户定义的类型重载符号。由于std::pair<int, int>
不是用户定义的类型,不允许。但是,对于您自己定义的结构或类, 是允许的。显然,在这种情况下,将重载置于命名空间更容易,而不是std
。
如果你把这个重载放在命名空间std
中,那么它将实际工作。
另请注意,boost::tuple
确实有operator<<
(在您必须包含的单独标题中,但确实如此),因此您可以使用它。