2012-03-18 3 views
2

여러 가지 유형으로 오버로드되는 매개 변수가있는 함수가 있다고 가정합니다. 예를 들어 :부분 템플릿 과부하

ostream& operator<<(ostream&, ...); 

내가 클래스 푸에게

class Foo { ... } 

이 그렇다면 내가 과부하

ostream& operator<<(ostream&, const Foo&); 

을 정의하고 그것을 잘 작동합니다.

template<class T> 
class vector {...} 

을 그리고 지금은 T가 유효한 유형을 할 수있는 vector<T> 걸리는 함수의 오버로드를 정의하려면 :

이제 나는 또 다른 클래스가 있다고 가정하자. 가능한 모든 입력 매개 변수에 대해 정의하지 않고이 작업을 수행 할 수 있습니까? 그러한 정의에 어떤 서명을 사용해야합니까?

template<class T> 
ostream& operator<<(ostream&, const vector<T>& v); 

?

배경 : 나는 실제로 표준에 대한 과부하를 쓰고 싶어이 경우

: 벡터 :

ostream& operator<<(ostream&, const std::vector<T>& x); 

같은 뭔가를 작성하는 "{2, 4, 8}" 내 로깅 시스템이 ostream의 최상위에 구축되어 있고 형식을 "문자열 화"하기 위해 내부적으로 연산자 < <을 사용하기 때문에 비슷합니다.

나는이 질문을 일반적으로 제기 할 것이라고 생각했지만이 경우에는 클래스 (예 : 벡터)를 변경할 수 없다는 제약 조건을 추가해야합니다.

template<class T> 
ostream& operator<<(ostream&, const vector<T>& v); 

이 부분 템플릿 특수화이 아니라 일반적인 함수를 오버로드 확인 규칙에 일치하는 기본 템플릿 기능 :

답변

4

일반적인 솔루션은 모두 ADL을 사용합니다. 첫 번째는 당신의 문제처럼 보이는 함수 템플릿을 쓰고있다 :

namespace ns { 
    // vector must reside in this namespace 

    template<typename T> 
    std::ostream& operator<<(std::ostream& os, vector<T> const& v); 
    // define somewhere 
} 

는 클래스 정의에 있기 때문에 다른 방법은 템플릿을 작성해야하지만 방해하지 않습니다

namespace ns { 
    template<typename T> 
    class vector { 
     /* stuff */ 
    public: 
     /* we're using the injected name for the class, 
      but vector<T> works just as well */ 
     friend 
     std::ostream& operator<<(std::ostream& os, vector const&) 
     { 
      /* caveat: must be defined inline 
       there's no other way to write the definitions for all T */ 
     } 
    }; 
} 
두 경우 모두

는, 클라이언트 코드는 다음과 같습니다

std::ostream& os = /* a stream from somewhere */; 
ns::vector<foo> v; 
os << v; // adl picks up correct overload 

당신은 아마 첫 번째 옵션을 사용해야하는 클래스에 대한 연산자를 구현할 때, 두 번째는 일반적으로 선택됩니다 (즉, 처음에는 vector이라고 쓰고 있습니다). 네임 스페이스의 특성으로 인해 ns::vector의 작가가 아니더라도 여기에 연산자를 넣으려면 namespace ns을 다시 열 수 있습니다.함수 템플리트는 부분적으로 특수화 될 수 없으며 여기서 전체 전문화를 사용할 수 없음을 명확히하기 위해 템플릿 전문화 작성 만 허용되기 때문에 이것이 namespace std 인 경우를 제외하고는 예외입니다. std::vector과 같은 것이 있으면 다음 마지막 옵션에 관심이있을 수 있습니다.


당신이 과부하를 추가하거나 namespace std에서 템플릿을 받아들이는 함수 템플릿을 작성하려면?

이것은 엄밀히 말하면 내 의견이지만, 그럴 수있는 유일한 방법은 확실합니다. 사용자가 선택한 네임 스페이스에 기능을 넣으십시오 (분명히 namespace std이 아니므로 다시 입력 할 수 없습니다) , 클라이언트 코드에서이를 요구하십시오. 같은

namespace stream_extensions { 

    template<typename T> 
    std::ostream& operator<<(std::ostream& os, std::vector<T> const& v); 
    // define somewhere 

} 

클라이언트 코드는 같습니다 네임 스페이스의 이름 만에 일의 제한된 수의 포함에 잘 선택 및 제한

std::ostream& os = /* stream from somewhere */; 
std::vector<T> v; 
// os << v; won't work, can't find relevant operator 
using namespace stream_extensions; 
os << v; // Okay, stream_extensions::operator<< is in scope 

하면, 나는 그런 using 지시문이 생각 매우 합리적인 선택. using namespace literals::chrono;을 예로 들어 보겠습니다. cond.wait(std::chrono::milliseconds(24)); 대신 cond.wait(24_ms);입니다.

이 기술의 큰 경고는 기능이 완전히 새로운 것임을 의미합니다.. 이것은 함수 템플릿에 대한 부분 전문화를 에뮬레이션하는 방법이 아닙니다. namespace std에 일반 함수 템플릿이있는 경우 ADL을 통해 선호되거나 매우 과도한 해상도 모호성으로 끝날 위험이 매우 큽니다. . 제한없는 template<typename T> std::ostream& operator<<(std::ostream& os, T const& t); (또는 유사한 회원 버전)이 없기 때문에 여기에 나온 예제는 의미가 있습니다.

+0

+1 매우 철저합니다. 아마도 OP는'std :: vector'와는 다른 또 다른'vector'를 구현하고 있습니다.이 경우 친구가 사용되어야합니다. 또한 "이 기능을 참조 할 수있는 방법이 없습니다"? 그것의 주소는 다른 과부하처럼'static_cast' 모호성 제거를 사용하여 찾을 수 있습니다. – Potatoswatter

+0

'참조 할 수있는 방법 없음'설명을 명확히했습니다. –

1

당신이 준 서명은 사용할 올바른 하나입니다.