2013-10-26 1 views
10

< <을 오버로드하여 범위 기반 루프 지원을 사용하는 모든 클래스에 대해 예쁜 인쇄를 구현하고 싶습니다. (잘못된) 코드는 이와 같습니다. 여기범위 기반 루프 지원을 사용하는 모든 클래스에 대해 예쁜 인쇄

template<class C> ostream& operator<<(ostream& out, const C& v) { 
    for(auto x : v) out<<x<<' '; 
    return out; 
} 

문제는이 < < 오버로드를 기존과 충돌 것입니다. C에서 원거리 기반 for 루프를 지원해야한다는 것을 템플릿에서 지정하는 방법이 있습니까?

답변

11

루프 범위 기반하기 때문에 ADL (및 std:: 관련 네임 스페이스 인)와 유효 begin(v)end(v)이 필요합니다, 당신은이를 사용할 수 있습니다

namespace support_begin_end 
{ 
    // we use a special namespace (above) to 
    // contain the using directive for 'std': 
    using namespace std; 

    // the second parameter is only valid 
    // when begin(C()) and end(C()) are valid 
    template<typename C, 
     typename=decltype(begin(std::declval<C>()),end(std::declval<C>())) 
    > 
    struct impl 
    { 
     using type = void; // only here impl 
    }; 

    // explicitly disable conflicting types here 
    template<> 
    struct impl<std::string>; 
} 

// this uses the above to check for ::type, 
// which only exists if begin/end are valid 
// and there is no specialization to disable it 
// (like in the std::string case) 
template<class C,typename = typename supports_begin_end::impl<C>::type> 
std::ostream& operator<<(std::ostream& out, const C& v) { 
    for(auto x : v) out<<x<<' '; 
    return out; 
} 

Live example

다른 유형이 있음 그러나 범위 기반 루프에 적합합니다. 당신도 그들을 감지 해야할지 모르겠다.


여기서 두 용기/v.begin()/v.end() 유형을 지원뿐만 아니라 begin(v)/end(v)을 지원 타입을 검출하는 갱신 live example이다.

+0

여기에 무슨 일이 일어나고 있는지 조금 설명해 주시겠습니까? 정말 고마워! – lfxgroove

+0

@lfxgroove 업데이트 된 답변이 도움이되는지 확인하십시오. –

+0

확실히, 힙 감사합니다! – lfxgroove

6

SFINAE : 모든 해답에

template<class C> 
auto operator<<(std::ostream& out, const C& v) -> decltype(v.begin(), v.end(), (out)) 
//           or -> decltype(std::begin(v), std::end(v), (out)) 
{ 
    for (auto x : v) 
     out << x << ' '; 
    return out; 
} 
4

일반적인 코멘트 :

이 많은 결과를 인쇄하기 전에 컬렉션 중 모든 요소를 ​​복사합니다

for (auto x : v) 

사용 복사 생성자와 소멸자에 대한 호출. 너는 아마도 더 편할거야

for (auto &x : v) 

.