2012-05-18 114 views
40

我有一个类使用嵌套类,并且想要使用嵌套类operator<<在上层类中定义operator<<。这里是我的代码看起来像:重载运算符<<:不能将左值绑定到'std :: basic_ostream <char> &&'

#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; 
} 
  • 当没有为C++ 11的支持编制,运营商< <为内部类的定义似乎不被编译器发现:

    与STD编译时
    so.hpp:24:7: error: no match for ‘operator<<’ in ‘out << tree.classA<int>::root’ 
    so.hpp:24:7: note: candidates are: ... 
    
  • 随着GCC 4.6和4.7 =的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]’ 
    

有人能告诉我为什么这段代码是不合法的,什么是做我想做的最好的方法?

回答

23

博提供的原因。这样做的一个简单的解决方法,有什么东西,我建议在一般情况下,不仅在这里,不亲民。一个模板,而是一个免费的功能对于您需要定义函数内联:

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 
    } 
}; 

有一对夫妇的两种方法之间的差异,最重要的是,这种做法将让编译器为定义一个非模板超载对于模板的每个实例,因为它不再是模板,不依赖于推导参数。另一个副作用是,这种方法有点更加紧密(你只与一个朋友函数,而在你最初的方法中,你结识了模板和所有可能的实例化(可以作为漏洞获得访问你的类内部)。最后这样定义的函数将只能通过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 _; 
    } 
} 

替代

或者,你可以交好模板的特定专业化。这将解决intruder问题,因为它只会对operator<<ClassA<intruder>开放,这个影响要小得多。但是这并不能解决你的问题,因为这个类型仍然不能被推断。

+0

感谢您提供解决方法。 – Antoine

+0

我看到它像一个*更好的设计*而不是*解决方法*。它有缺点(你不能把模板类中声明的朋友函数的地址),但在所有其他帐户上,它更适合提供免费函数操作符... –

+0

这是[Making New Friends](https ://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Making_New_Friends)成语,所以不是真正的解决方法。 – TBBle

28

你在这个操作符

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

编译器有一个"non-deducible context"问题想不通的T值将导致classB要传递参数相匹配的内容。所以这个模板不被考虑!

在C++ 11模式下,编译然后继续找到标准库

operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) 

一场势均力敌的比赛在那里可以比赛_Tp到几乎任何类型的,包括classA<T>::classB,但笔记第一个参数不匹配。

+1

关于近距离比赛的评论清楚说明为什么我有类似的问题。 –

2

试试这个:

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

,然后你会得到不称职的直接表白:

test.cpp:34:3: error: no matching function for call to ‘operator<<(std::ostream&, const classA<int>::classB&)’ 
test.cpp:34:3: note: candidates are: 
test.cpp:23:22: note: template<class T> std::ostream& operator<<(std::ostream&, const  typename classA<T>::classB&) 
test.cpp:30:22: note: template<class T> std::ostream& operator<<(std::ostream&, const classA<T>&) 

解决方法:或许你可以在嵌套CLASSB用一个成员函数,并用它来代替操作员< < ...当然,该解决方案有许多缺点,但它可能会让您摆脱这种匆忙。为什么发生这种情况(类型T是不是在调用嵌套operator<<抵扣

+1

您可以总是显式调用':: operator << (out,tree.root)',但我认为现在命名的成员函数看起来更有吸引力。 – Useless

相关问题