错误:无法将‘std::basic_ostream<char>’左值绑定到‘std::basic_ostream<char>&&’

Posted

技术标签:

【中文标题】错误:无法将‘std::basic_ostream<char>’左值绑定到‘std::basic_ostream<char>&&’【英文标题】:error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’ 【发布时间】:2012-11-12 16:30:40 【问题描述】:

我已经看过几个关于这个的问题,特别是Overloading operator<<: cannot bind lvalue to ‘std::basic_ostream<char>&&’ 很有帮助。它让我知道我的问题是我正在做一些 c++11 无法从中推断出类型的事情。

我认为我的问题的很大一部分是我正在使用的实例化类是模板化的,但最初是从指向非模板基类的指针中获得的。这是我从另一个关于如何将模板类对象放入 STL 容器的 ***.com 问题中建议的。

我的课:

class DbValueBase 
  protected:
    virtual void *null()  return NULL;    // Needed to make class polymorphic
;

template <typename T>
class DbValue : public DbValueBase 
  public:
    DbValue(const T&val)   data = new T(val); 
    ~DbValue()  if (data) delete data; 

    T   *data;

    const T&    dataref() const  return *data;  

    friend std::ostream& operator<<(std::ostream& out, const DbValue<T>& val)
    
        out << val.dataref();
        return out;
    

还有,出现编译错误database.cc:530:90: error: cannot bind ‘std::basic_ostream&lt;char&gt;’ lvalue to ‘std::basic_ostream&lt;char&gt;&amp;&amp;’的代码sn-p:

//nb:  typedef std::map<std::string,DbValueBase*>  DbValueMap;
    const CommPoint::DbValueMap&    db_values = cp.value_map();
    for (auto i = db_values.cbegin() ; i != db_values.cend() ; i++) 
        // TODO: Need to implement an ostream operator, and conversion
        // operators, for DbValueBase and DbValue<>
        // TODO: Figure out how to get a templated output operator to
        // work... 
 //     DbValue<std::string> *k = dynamic_cast<DbValue<std::string>*>(i->second);
        std::cerr << "  Database field " << i->first << " should have value " << *(i->second) << endl;
    

如果我的输出尝试打印i-&gt;second,它会编译并运行,我会看到指针。如果我尝试输出 *(i-&gt;second),我会收到编译错误。在 gdb 中单步执行时,它似乎仍然知道i-&gt;second 是正确的类型

(gdb) p i->second
$2 = (DbValueBase *) 0x680900
(gdb) p *(i->second)
warning: RTTI symbol not found for class 'DbValue<std::string>'
$3 = warning: RTTI symbol not found for class 'DbValue<std::string>'
_vptr.DbValueBase = 0x4377e0 <vtable for DbValue<std::string>+16>
(gdb) quit

我希望我做错了什么。但是,它比我自己似乎能够弄清楚的要复杂得多。其他人看到我做错了什么或不完整的事情吗?

编辑:

@PiotrNycz 确实为我在下面提出的问题提供了一个很好的解决方案。然而,尽管目前在进行开发时会打印值,但这些DbValue&lt;&gt; 对象的真正需要是让它们返回正确类型的值,然后我可以将其提供给数据库操作方法。我应该在我最初的问题中提到,印刷是有价值的,但不是我目标的终点。

【问题讨论】:

virtual void *null() return NULL; // Needed to make class polymorphic 相反,您可以只声明析构函数为虚拟的,无论如何您都需要这样做。 virtual ~DbValueBase() = default; @barnes53 谢谢。这意味着我必须将noexcept (true) 添加到模板子类析构函数中,这与default 有关,我敢肯定,但比未使用的方法更干净。谢谢。 【参考方案1】:

如果你想通过基指针打印对象 - 在基类中创建 ostream 运算符:

class DbValueBase 
  protected:
    virtual ~DbValueBase() 
    virtual void print(std::ostream&) const = 0;
    friend std::ostream& operator << (std::ostream& os, const DbValueBase & obj)
    
       obj.print(os); return os;
    
;

template <typename T>
class DbValue : public DbValueBase 
  public:
    void print(std::ostream& os) const 
    
        out << dataref();
    
;

【讨论】:

谢谢。很抱歉,我无法弄清楚如何让编译器找出正确的 DbValue::operatorif dynamic_cast<Foo<A>> else dynamic_cast<Foo<B>> else ...。 :-) 但是,我意识到我只是在谈论打印,因为这就是我目前正在做的事情。但是,我还需要将这些对象转换为模板类型,因为我需要将它们插入到数据库中。您的解决方案适用于执行操作,但不适用于返回值。也许我应该扩展我原来的问题来表明这一点。 @cross 这是通用方法。试试这个:virtual void DbValueBase::insertMe(Database&amp; db) = 0; 【参考方案2】:

尽管调试器将*(i-&gt;second) 正确识别为DbValue&lt;std::string&gt; 类型,但该确定是使用仅在运行时可用的信息做出的。

编译器只知道它正在使用DbValueBase&amp;,并且必须在此基础上生成它的代码。因此,它不能使用operator&lt;&lt;(std::ostream&amp;, const DbValue&lt;T&gt;&amp;),因为它不接受DbValueBase 或子类。


为了通过DbValueBase&amp; 获取DbValue&lt;&gt; 对象的内容,您可能需要循环进入访问者设计模式。

一些示例代码:

class Visitor 
public:
    template <typename T>
    void useValue(const T& value);
;

class DbValueBase 
public:
    virtual void visit(Visitor&) = 0;
;

template <class T>
class DbValue : public DbValueBase 
pblic:
    void visit(Visitor& v) 
        v.useValue(m_val);
    
private:
    T m_val;
;

【讨论】:

我得看看这是否适合我的需要。我想有效地返回值,这似乎并没有适应。我需要看看我是否可以编写一个访问者函数来应用这些值。当我更接近使用数据值对象时,我会有一个更好的主意。感谢您的指点/建议! 在我的情况下弄清楚如何使用访问者设计模式将值 (typename T) 作为参数应用到对象有点复杂,但能够做到。只需在构建过程中将对象构建到访问者中,然后就可以像上面的示例一样使用它。现在这是公认的答案。再次感谢!

以上是关于错误:无法将‘std::basic_ostream<char>’左值绑定到‘std::basic_ostream<char>&&’的主要内容,如果未能解决你的问题,请参考以下文章

如何将数组和输出转移到 ofstream 写入?

‘operator<<’ 不匹配(操作数类型是 ‘std::ostream’ aka ‘std::basic_ostream<char>’ 和 ‘const std::type

链接 C++ 程序时出错

std::chrono 和 cout

Ruby 内核命令

删除动态数组时崩溃