【问题标题】:boost::variant and operator<< overloadingboost::variant 和 operator<< 重载
【发布时间】:2014-04-25 18:39:24
【问题描述】:

我想测试一个简单的东西,如下所示:

#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 有一个打印机访问器,它在内部使用它来将内容输出到流中。 实际上这无法编译,但我真的不知道问题所在:

代码在此处失败:在 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>&&'

有人知道我做错了什么,为什么?

非常感谢!

【问题讨论】:

  • 这不是我们需要知道才能诊断问题的地方。当模板定义出现问题时,编译器会打印扩展链。我们需要完整的输出来告诉你发生了什么。
  • 由于错误消息似乎来自 MSC++,我会提到您需要从 Visual Studio 的“输出”选项卡中获取消息,“错误”窗口已过滤掉注释并对目的没有用。注释紧跟错误消息。
  • think...think...think... 这次的答案其实很简单。不过,这不是草率问题的借口;每当询问编译问题时,complete 编译器输出是mandatory
  • 抱歉转储问题:我在上面的问题中添加了解决方案,在下面的其他帖子中也提到了
  • @Gabriel 请不要编辑您的问题以让其他人知道问题已解决。将答案标记为已接受。

标签: c++11 operator-overloading ostream boost-variant


【解决方案1】:

很可能它没有找到您的 operator &lt;&lt; 过载,然后在尝试匹配其他过载时感到困惑,从而导致您收到任何消息。

您做错了什么:您在全局命名空间中重载了流运算符,而不是在定义右侧类的命名空间中,因此 ADL 找不到它。

不幸的是,试图重载标准类的流运算符首先是注定要失败的。你实际上不能那样做。我不确定是否有明确的规则反对它。但是,如果您将运算符放置在命名空间 std 中,以便 ADL 正确找到它,则您违反了不能将自己的东西添加到命名空间 std 的规则,除非在非常特殊的情况下,这不是其中之一。

底线是std::pair 没有流运算符,并且不可能合法地添加有用的通用运算符。如果其中一个参数是您自己定义的类,您可以为特定实例添加一个;在这种情况下,运算符需要放在您自己的类旁边。

【讨论】:

  • 有一条规则说你不能在std命名空间中放任何东西,除了为用户定义的类型重载它的符号。
【解决方案2】:

重载的operator&lt;&lt; 必须可以通过参数相关查找找到。这意味着您必须将其放在其中一个参数的关联命名空间中。

第一个参数只有一个关联的命名空间std。第二个也只有一个关联的命名空间std。但是,对于用户定义的类型,只允许重载 std 中的符号。由于std::pair&lt;int, int&gt;不是用户定义的类型,这是不允许的。但是, 允许用于您自己定义的结构或类。显然,在这种情况下,将重载放置到命名空间而不是 std 会更容易。

也就是说,如果您将该重载放在命名空间 std 中,它真正起作用。

另请注意,boost::tuple 确实有 operator&lt;&lt;(在您必须包含的单独标题中,但确实包含),因此您可以使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-05
    相关资源
    最近更新 更多