重载操作符<&lt ;:不能将lvalue绑定到'std :: basic_ostream< char>&& [英] Overloading operator<<: cannot bind lvalue to ‘std::basic_ostream<char>&&’

查看:4799
本文介绍了重载操作符<&lt ;:不能将lvalue绑定到'std :: basic_ostream< char>&&的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用嵌套类的类,并且想要使用嵌套类 operator 定义运算符<< / code>在上层类。这里是我的代码看起来像:

  #include< memory& 
#include< iostream>

template< typename T>
struct classA {
struct classB
{
template< typename U>
friend inline std :: ostream&运算符<< (std :: ostream& out,
const typename classA< U> :: classB& b);
};

classB root;

template< typename U>
friend std :: ostream&运算符<< (std :: ostream& out,
const classA< U>& tree);
};

template< typename T>
inline std :: ostream&运算符<< (std :: ostream& out,
const classA< T>& tree)
{
out<树木
return out;
}

template< typename T>
inline std :: ostream&运算符<< (std :: ostream& out,
const typename classA< T> :: classB& b)
{
return out;
}

int main()
{
classA< int>一个;
std :: cout<<一个;
}




  • ++ 11,operator<<<对于内部类似乎没有被编译器找到:

      so.hpp:24:7:error:no match for 'operator<<'in'out<< tree.classA< int> :: root'
    so.hpp:24:7:note:candidates are:...

    li>

  • 在使用std = c ++ 0x:

    时编译GCC 4.6和4.7时,

      so.hpp:21:3:error:can not bind'std :: ostream {aka std :: basic_ostream< char>}'lvalue to'std :: basic_ostream< char>&包括从/usr/include/c++/4.7/iostream:40:0,
    从so.hpp:2:
    /usr/include/c++/4.7/ostream:600:5:错误:初始化'std :: basic_ostream< _CharT,_Traits>的参数1 std :: operator<<<(std :: basic_ostream< _CharT,_Traits>&&&& const _Tp&)[with _CharT = char; _Traits = std :: char_traits< char> ;; _Tp = classA< int> :: classB]'




有人可以告诉我为什么这个代码不合法​​,什么是最好的方式来做我想要的?

解决方案

T 不能在调用嵌套的运算符<< 。一个简单的解决方法,我推荐一般,不仅仅是在这里,不是一个模板,而是一个单一的自由函数,为此你需要 define 函数inline:

 模板< typename T> 
struct classA {
struct classB
{
friend inline std :: ostream& operator<<(std :: ostream& out,
const classB& b){
//定义在这里
}
};

classB root;

friend std :: ostream& operator<<<(std :: ostream& out,
const classA< U> & tree){
// definition here here
}
};

这两种方法有几个区别。最重要的是,这种方法将使编译器为模板的每个实例化定义 operator 的非模板化重载,这是因为它不再是模板,不依赖于推导参数。另一个副作用是,该方法有点更紧密(你只是一个函数),而在你的初始方法中,你结合模板和所有可能的实例化(可以是最后,这样定义的函数只能通过ADL找到,所以对于 operator 的重载更少了编译器考虑当参数不是 ClassA< T> ClassA< T> :: ClassB






如何获得使用方法

  namespace {
struct intruder {
ClassA& ref;
intruder(ClassA& r):ref(r){}
};
template<>
std :: ostream& operator<<< intruder>(std :: ostream& _,ClassA< intruder> const& i){
std :: cout<< i.ref.private_member<< std :: endl;
return _;
}
}

替代 >

或者,您可以熟悉模板的特殊化。这将解决入侵者问题,因为它只对运算符 ClassA< intruder> ,其影响要小得多。但这不会解决你的特定问题,因为类型仍然不可推断。


I have a class that uses a nested class, and want to use the nested class operator<< to define operator<< in the upper class. Here is how my code looks like:

#include <memory>
#include <iostream>

template<typename T>
struct classA {
  struct classB
  {
    template<typename U>
    friend inline std::ostream& operator<< (std::ostream &out,
                                            const typename classA<U>::classB &b);
  };

  classB root;

  template<typename U>
  friend std::ostream& operator<< (std::ostream &out,
                                   const classA<U> &tree);
};

template<typename T>
inline std::ostream& operator<< (std::ostream &out,
                                 const classA<T> &tree)
{
  out << tree.root;
  return out;
}

template<typename T>
inline std::ostream& operator<< (std::ostream &out,
                                 const typename classA<T>::classB &b)
{
  return out;
}

int main()
{
  classA<int> a;
  std::cout << a;
}

  • When compiling without support for C++11, the definition of operator<< for the inner class seems not to be found by the compiler:

    so.hpp:24:7: error: no match for ‘operator<<’ in ‘out << tree.classA<int>::root’
    so.hpp:24:7: note: candidates are: ...
    

  • With GCC 4.6 and 4.7 when compiling with std=c++0x:

    so.hpp:21:3: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
    In file included from /usr/include/c++/4.7/iostream:40:0,
                     from so.hpp:2:
    /usr/include/c++/4.7/ostream:600:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = classA<int>::classB]’
    

Can someone tell me why this code is not legal, and what's the best way to do what I want?

解决方案

Bo provided the reason why this is happening (the type T is not deducible in the call to the nested operator<<. A simple workaround for this, and something that I recommend in general, not only here, is not befriending a template, but rather a single free function. For that you will need to define the function inline:

template<typename T>
struct classA {
  struct classB
  {
    friend inline std::ostream& operator<< (std::ostream &out,
                                            const classB &b) {
       // definition goes here
    }
  };

  classB root;

  friend std::ostream& operator<< (std::ostream &out,
                                   const classA<U> &tree) {
       // definition goes here
  }
};

There are a couple of differences among the two approaches. The most important one is that this approach will have the compiler define a non-templated overload for operator<< for each instantiation of the template, which because it is no longer a template, does not depend on deducing the arguments. Another side effects are that the approach is a little tighter (you are only befriending one function, while in your initial approach you befriended the template and all possible instantiations (which can be used as a loophole to gain access to your class internals). Finally the functions so defined will only be found through ADL, so there are less overloads of operator<< for the compiler to consider when the argument is not ClassA<T> or ClassA<T>::ClassB.


How access can be gained with your approach

namespace {
   struct intruder {
       ClassA & ref;
       intruder( ClassA& r ) : ref(r) {}
   };
   template <>
   std::ostream& operator<< <intruder>( std::ostream& _, ClassA<intruder> const& i ) {
       std::cout << i.ref.private_member << std::endl;
       return _;
   }
}

Alternative

Alternatively you can befriend a particular specialization of a template. That will solve the intruder problem, as it will only be open to operator<< to ClassA<intruder>, which has a much lesser impact. But this will not solve your particular issue, as the type would still not be deducible.

这篇关于重载操作符&lt;&lt ;:不能将lvalue绑定到'std :: basic_ostream&lt; char&gt;&amp;&amp;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆