2

나는 다음과 같은 그것에 템플릿 클래스 및 출력 연산자를 작성했습니다 :출력 연산자는

#include <iostream> 

namespace N 
{ 

template< typename ...types > 
struct X 
{ 
    static_assert((sizeof...(types) != 0), "zero length"); 
    X() = default; 
    X(X const &) = default; 
    X(X &&) = default; 
    template< typename ...args > 
    //explicit // does not matter 
    X(args &&...) { ; } 
    int value = 10; 
}; 

template< typename ...types > 
std::ostream & 
operator << (std::ostream & out, X<types...> const & x) 
{ 
    return out << x.value; 
} 

} // namespace N 

int main() 
{ 
    using namespace N; 
    X<float> /*const*/ x; // `const` does not matter 
    std::cout << x << std::endl; 
    return 0; 
} 

그러나 static_assert 이온을 제기 :

main.cpp:9:5: error: static_assert failed "zero length" 
    static_assert((sizeof...(types) != 0), "zero length"); 
    ^   ~~~~~~~~~~~~~~~~~~~~~~~ 
main.cpp:32:23: note: in instantiation of template class 'N::X<>' requested here 
    std::cout << x << std::endl; 
        ^
1 error generated. 

만약 클래스 템플릿 X 전역에 namespace에 정의 된 operator << 오버로드는 모두 동일합니다. 내가 알기로, 그 대답은 using namespace N; 라인과 대체 X<float>에서 N::X<float>로 해결됩니다.

어떻게 이런 행동을 설명 할 수 있습니까? 그 원인은 무엇입니까?

편집 : 나는 해결책을 찾을 수

은 : 클래스의

template< typename first, typename ...rest > 
std::ostream & 
operator << (std::ostream & out, X< first, rest... > const & x) 
{ 
    return out << x.value; 
} 

분할 typename ..types이 nessesarily되지 않습니다 : 다음과 같이 오버로드 operator <<의 템플릿 매개 변수를 CHAGE하는 것입니다. 게다가 극단적 인 코드의 팽창으로 인해 결과가 전혀 바람직하지 않습니다.

+0

중복 된'std :: endl' 대신' '\ n''을 사용하면 역시 수정됩니다. – Cubbi

답변

5

문제 재현하는 간단한 방법 :이 경우

int main() 
{ 
    using namespace N; 
    std::cout << std::endl; 
} 

를 후보 함수는 모든 namespace std에서 operator<<의 과부하, < < 년대 std::ostream의 모든 멤버 연산자 및 namespace N에서 함수 템플릿 operator<<은 .

13.3.1/7 : 그래서

, 오버로드 확인이 시작하기 전에, X<types...> const&std::endl에서 추론 할 수있다 "후보 함수 템플릿이고, 후보 함수 템플릿 특수화 템플릿 인수 추론을 사용하여 생성된다" 이것은 템플릿 함수의 주소이다. 함수의 주소는 함수 포인터 유형이며 N::X<types...> const&을 포인터 유형과 일치시키는 유일한 방법은 types...을 빈 목록으로 추론하는 것입니다.

(함수 포인터 유형에서 N::X<>으로의 암시 적 변환이 없기 때문에 물론 대체 할 수 없기 때문에 과부하를 조용히 제거 할 수는 없지만 정적 어설 션은 즉각적인 컨텍스트가 아니며 하드 오류입니다.

이야기의 도덕 : 사용 지시어은 악합니다.

+0

좋은 설명. 그러나'타입 ... '을 빈리스트로 추론하는 것은 충분히 명확하지 않습니다. – Orient

+0

'N :: X < types... > const &'는'decltype (std :: endl)'유형의 포인터로 취급 될 수 있습니까? – Orient

+1

이 대답에 대한 답으로'template struct X'를'template struct X'로 대체하면 문제가 해결 될 것입니다. – Orient