2016-09-05 2 views
2

(다중) 파생 클래스를 기본 클래스를 예상하는 템플릿 함수에 전달할 때 템플릿 인스턴스화 규칙은 무엇입니까? 예를 들면 : - 1 6.2 GCC 컴파일러 에러 (Demo)를 제공여러 템플릿 상속을 사용한 템플릿 인스턴스화

#include <iostream> 

template <int x> 
struct C {}; 

struct D : C<0>, C<1> {}; 

template <int x> 
void f (const C<x> &y) { std::cout << x << "\n"; } 

int main() 
{ 
    f (D()); 
} 

MSVC 2,015 인쇄 0 3.8 연타. 심지어 SFINAE - 멀리 모든 오버로드를 제외한 당신이 경우에, 결과는 여전히 다를 것이다 :

#include <iostream> 

template <int x> struct C {}; 

template<> 
struct C<0> { using type = void; }; 

struct D : C<0>, C<1> {}; 

template <int x, typename = typename C<x>::type> 
void f (const C<x> &y) { std::cout << x << "\n"; } 

int main() 
{ 
    f (D()); 
} 

가 지금은 MSVC로 컴파일하고 C<0>C<1>를 교환 할 경우에만 그 소리가 컴파일됩니다. 문제는 MSVC가 첫 번째 기본, clang - last 및 gcc 오류를 너무 일찍 인스턴스화하려고 시도한다는 것입니다. 어느 컴파일러가 옳은가?

+0

나는 마치 그들이 모두 잘못되었다고 생각합니다. 모호한 함수 호출이 아니어야합니까? –

+0

* "MSVC는 0, clang - 1을 출력하고 gcc는 컴파일러 오류를 발생시킵니다."*, 어느 MSVC, 어느 gcc와 어느 clang? –

+0

@PiotrSkotnicki 버전 번호를 추가했지만 모두 동일하게 동작합니다. –

답변

1

GCC 5.4 :

/tmp/gcc-explorer-compiler11685-58-1h67lnf/example.cpp: In function 'int main()': 
13 : error: no matching function for call to 'f(D)' 
f (D()); 
^ 
9 : note: candidate: template<int x> void f(const C<x>&) 
void f (const C<x> &y) { std::cout << x << "\n"; } 
^ 
9 : note: template argument deduction/substitution failed: 
13 : note: 'const C<x>' is an ambiguous base class of 'D' 
f (D()); 
^ 
Compilation failed 

날 것으로 보인다 C < 0>와 C < 1 일 이후> 똑같이 전문화되어, 올바른 결과가 될 수 있습니다. GCC 6.2

그 소리 3.8.1에 대한

같은 결과를 내보기에 컴파일러의 버그 인을 컴파일합니다.

갱신 :

나는 실제 사용 사례를 모르지만 나는이 당신을 위해 작동 할 수 있는지 궁금했다 :

#include <utility> 
#include <iostream> 

template<class T> 
struct has_type 
{ 
    template<class U> static auto test(U*) -> decltype(typename U::type{}, std::true_type()); 
    static auto test(...) -> decltype(std::false_type()); 
    using type = decltype(test((T*)0)); 
    static const auto value = type::value; 
}; 

template <int x> struct C {}; 

template<> 
struct C<0> { using type = int; }; 

template<int...xs> 
struct enumerates_C : C<xs>... 
{ 
}; 

struct D : enumerates_C<0, 1> {}; 

template<int x, std::enable_if_t<has_type<C<x>>::value>* = nullptr> 
void f_impl(const C<x>& y) 
{ 
    std::cout << x << "\n"; 
} 

template<int x, std::enable_if_t<not has_type<C<x>>::value>* = nullptr> 
void f_impl(const C<x>& y) 
{ 
    // do nothing 
} 

template <int...xs> 
void f (const enumerates_C<xs...> &y) 
{ 
    using expand = int[]; 
    void(expand { 0, 
     (f_impl(static_cast<C<xs> const &>(y)),0)... 
    }); 
} 

int main() 
{ 
    f (D()); 
} 

예상 출력 (사과 연타 테스트) :

0 
+0

첫 번째 예에서 - 예, 모호해야한다고 생각합니다. 두 번째로는 아니요. C에 대한 오버로드 만 허용됩니다. <0>을 사용해야합니다. –

+0

"* C의 오버로드 만 <0>을 활성화해야합니다 *"컴파일러가 각 가능한 'x'를 사용하려고 시도해야한다고 생각합니까? 첫 번째 공제가 발생합니다. 실패합니다. –

+0

@PiotrSkotnicki이 질문을 통해 어떻게해야하는지 배우게됩니다. 이 함수를 수동으로 작성하면 의도 한대로 작동합니다. https://gist.github.com/telishev/a52483833ae6850df69e1e6953f6b277 –