重载操作符<< ;:不能将lvalue绑定到'std :: basic_ostream< char>&& [英] Overloading operator<<: cannot bind lvalue to ‘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
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.
这篇关于重载操作符<< ;:不能将lvalue绑定到'std :: basic_ostream< char>&&的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!