2013-07-28 2 views
2

나는 문제표준 : : ostream에 & 연산자 << 형태 추론

을 재현하기 위해 하나

#include <list> 
#include <iostream> 

template<typename T> 
std::ostream& operator<<(std::ostream& out, const std::list<T>& list){ 
    out << "["; 
    if(!list.empty()){ 
     typename std::list<T>::const_iterator it = list.cbegin(); 
     out << *it; 
     for (++it; it != list.cend(); ++it){ 
      out << ", "; 
      out << *it; 
     } 
    } 
    out << "]"; 
    return out; 
} 

같은 템플릿 함수와 중첩 된 클래스

namespace my{ 

    template< 
     typename T, 
     typename U = size_t 
    > 

    class graph{ 

    public: 
     typedef T dist_t; 
     typedef U node_t; 

     class node_pt; 
     typedef struct arc_t{ 
      node_pt* from = nullptr; 
      node_pt* to = nullptr; 
      dist_t weight; 
     } arc_t; 
     typedef struct arc_pt{ 
      arc_t arc; 
     } arc_pt; 
     typedef struct node_pt{ 
      node_t node; 
     } node_pt; 

     class arc_iterator{ 
     public: 
      arc_pt* pt = nullptr; 
     public: 
      arc_pt* operator->() const{ 
       return pt; 
      } 

      friend std::ostream& operator<< (std::ostream &out, const arc_iterator& it) { 
       out << "(" << it->arc.from->node << "," << it->arc.to->node << "," << it->arc.weight << ")"; 
       return out; 
      } 
     }; 

     class node_iterator{ 
     public: 
      node_pt* pt = nullptr; 

     public: 

      node_t operator *() const{ 
       return pt->node; 
      } 

      friend std::ostream& operator<< (std::ostream &out, const node_iterator& it) { 
       out << *it; 
       return out; 
      } 
     }; 

    }; 
} 

일부 코드 일부 템플릿 클래스가
namespace my{ 
    namespace test{ 
     void run(){  
      typedef my::graph<size_t> graph_t; 
      std::list<graph_t::node_t> l1; 
      std::list<graph_t::dist_t> l2; 
      std::list<graph_t::node_iterator> l3; 
      std::list<graph_t::arc_iterator> l4; 

      std::cout << l1 << std::endl; 
      std::cout << l2 << std::endl; 
      std::cout << l3 << std::endl; 
      std::cout << l4 << std::endl; 
     } 
    } 
} 


int main(){ 
    my::test::run(); 
} 

두 친구 방법을 정의하면 문제가 발생하지 않습니다. 하나의 메서드 만 정의하고 반복자 목록 인쇄 중 하나에 주석을 달면 작동합니다. 내가 갖는

오류가

src/OTest_Graph.cpp: In member function ‘virtual void my::test::TestGraph::run()’: 
src/OTest_Graph.cpp:59:53: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’ 
In file included from /usr/include/c++/4.7/iostream:40:0, 
       from h/OTest_Graph.h:4, 
       from src/OTest_Graph.cpp:1: 
/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 = std::list<my::graph<long unsigned int>::node_iterator, std::allocator<my::graph<long unsigned int>::node_iterator> >]’ 

사람이 여기에 무슨 일이 일어나고 있는지 말해 줄 수 있습니까?

답변

1

, @matt-whitlock's answer를 참조 그 ... 내가 찾은 전부입니다.

g++ 4.7를위한 솔루션 :

대신 내가 전역 네임 스페이스에 선언 된 다음 연산자와 같은 문제가 있었다

::operator<<(std::cout, l1) << std::endl; 
::operator<<(std::cout, l2) << std::endl; 
::operator<<(std::cout, l3) << std::endl; 
::operator<<(std::cout, l4) << std::endl; 
4

코드는 clang ++에서 나를 위해 컴파일되고 실행됩니다. 이 컴퓨터에서 g ++로 시도 할 수 없습니다.

편집 : 실제로 g ++로 컴파일됩니다. 이는 사용자가 글로벌 네임 스페이스에있는 메인에서 operator<< 만 사용하기 때문에 의미가 있습니다. 나는 당신의 실제 코드 편집

\ 다른 가정하지만

방법을 설명하는 오류 "ostream에 & &에 바인딩 할 수 없습니다 ostream에의 좌변"를 잘 알고 있어요. 이 ostreams 사이 operator<<std 클래스 제공하는 문제 (당신의 예제처럼 list은,하지만 난 vector로 발견)

은 대부분 작동하지만, 운영자가 네임 스페이스에서 호출 될 때 (당신의 my 네임 스페이스 등) 그것은 부서진다.

왜? "이 연산자는 어디에서 찾을 수 있습니까? < < 회원"이니까요? Ostream과 목록 사이에 많은 다른 연산자가있을 수 있습니다. < < 그렇다면 컴파일러는 어디에서 그것을 찾습니까?

각 피연산자의 네임 스페이스를 찾습니다 (두 경우 모두 std). 그리고 가끔 (귀하의 경우 my) 네임 스페이스에 있습니다.

표준에 따르면 안되기 때문에 "때때로"라고 말하지만, 어쨌든 g ++은 그렇게합니다. 당신은 std 네임 스페이스 내에서 운영자 < <을 넣고 싶어하지만,

이상적으로 (그것이 나를 위해 일한 따라서 이유) 대신 글로벌 네임 스페이스에 보이는 - 그 소리 ++하지 않습니다 (그것을 시도 - 그것은 작동합니다). 하지만 표준에 위배됩니다. 당신은 그렇게 할 수 없습니다. my 네임 스페이스에 넣을 수 있으며 g ++에서 찾을 수 있지만 다른 컴파일러에서는 사용할 수 없습니다.

문제가 있습니다. 래퍼 (wrapper)를 만들어 내 자신의 네임 스페이스에 존재하는 클래스이며 std 클래스에 대한 참조 만 보유하고이를 인쇄하여 인쇄 할 수 있습니다.

template<class T> struct OutList<T>{ 
    const std::list<T> &lst; 
    OutList(const std::list &l):lst(l){} 
}; 

template<class T> OutList<T> outlist(const std::list<T> &lst){return OutList<T>(lst);} 

std::ostream &operator<<(std::stream &out,const OutList<T> &lst){...} 

.... 
std::cout << "list= "<<outlist(list)<<std::endl; 

은 꽤 아니지만,

오류가 표준 라이브러리의 버전에 따라 다릅니다
+0

그럼 실제로 내 _main_ 코드가 내 :: 테스트 네임 스페이스에 내가'작성하는 경우 :: 연산자 << (std :: cout, l1);'컴파일 ... –

+0

g ++ 대신 clang으로 이동하여 미래의 C++ 프로젝트에 사용할 것을 권합니다. –

+1

아니요, 모든 컴파일러에서 컴파일되는 코드를 작성하는 것이 좋습니다. 덜 예쁘지 만, 모든 것을 컴파일하는 코드를 작성하는 것은 매우 중요합니다. – rabensky

1

사용

std::cout << l1 << std::endl; 
std::cout << l2 << std::endl; 
std::cout << l3 << std::endl; 
std::cout << l4 << std::endl; 

의 :

명명 된 네임 스페이스에 선언 된 함수에서 호출
template <typename T> 
std::ostream & operator << (std::ostream &os, const std::vector<T> &vector); 

은 ... :

std::ostream & operator << (std::ostream &os, const Foo &foo) { 
    return os << foo.items; // error 
} 

... Foo::itemsstd::vector입니다. 악명 높은 오류를 제공 ++

g :

error: cannot bind 'std::basic_ostream<char>' lvalue to 'std::basic_ostream<char>&&' 

C++ 11 <ostream>에서 주석이로 설명하는 포괄 std::operator << 템플릿을 도입하기 때문에 오류가 발생 "를 rvalue 스트림에 대한 일반적인 삽입을." 인수 종속적 인 조회가 먼저 std::operator << 템플릿을 찾으면 컴파일러는 전역 ::operator << 템플릿을 찾지 못합니다.

간단하고 정확한 수정이 using 선언으로 로컬 범위에 글로벌 연산자를 가지고하는 것입니다

std::ostream & operator << (std::ostream &os, const Foo &foo) { 
    using ::operator <<; 
    return os << foo.items; // OK 
} 
+0

그래서 컴파일러가 아닌이 오류가 발생하는 표준 라이브러리입니다. 나는 내 대답을 편집 할 것이다. –