簡體   English   中英

重載operator <<:無法將左值綁定到'std :: basic_ostream <char> &&'

[英]Overloading operator<<: cannot bind lvalue to ‘std::basic_ostream<char>&&’

我有一個使用嵌套類的類,並希望使用嵌套類operator<< operator<<在上層類中定義operator<< 以下是我的代碼的樣子:

#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的情況下進行編譯時,編譯器似乎找不到內部類的operator <<的定義:

     so.hpp:24:7: error: no match for 'operator<<' in 'out << tree.classA<int>::root' so.hpp:24:7: note: candidates are: ... 
  • 使用std = c ++ 0x進行編譯時使用GCC 4.6和4.7:

     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]' 

有人能告訴我為什么這段代碼不合法​​,什么是做我想要的最好的方法?

您在此運算符中遇到“不可導入的上下文”問題

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

編譯器無法確定哪個T值會導致classB與您要傳遞的參數匹配。 所以這個模板不予考慮!

在C ++ 11模式下,編譯器繼續從標准庫中找到一個緊密匹配

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

可以匹配_Tp幾乎任何類型,包括classA<T>::classB ,但注意第一個參數不匹配。

Bo提供了為什么會發生這種情況的原因 (類型T在嵌套operator<<的調用中是不可推斷的。這是一個簡單的解決方法,我推薦的一般情況,不僅僅是在這里,不是模板的朋友,而是而是一個單獨的自由函數。為此你需要定義內聯函數:

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

這兩種方法有兩點不同。 最重要的一點是,這種方法將使編譯器為模板的每個實例化定義operator<<的非模板化重載,因為它不再是模板,不依賴於推導參數。 另一個副作用是方法更緊湊 (你只是與一個函數交朋友,而在你最初的方法中,你結識了模板和所有可能的實例化(可以作為漏洞來獲得對你的類內部的訪問)。這樣定義的函數只能通過ADL找到,因此當參數不是ClassA<T>ClassA<T>::ClassB時,編譯器要考慮的operator<<重載次數較少。


如何通過您的方法獲得訪問權限

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<< to ClassA<intruder> ,后者的影響要小得多。 但這不會解決您的特定問題,因為該類型仍然無法推斷。

試試這個:

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中使用成員函數,並使用它而不是運算符<< ...當然,該解決方案有許多缺點,但它可能會讓您擺脫這種匆忙。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM