모호한 템플릿 이상함
-
19-09-2019 - |
문제
다음 코드가 있습니다 (대형 코드 청크에 대해 죄송하지만 더 이상 좁을 수 없었습니다).
template <bool B>
struct enable_if_c {
typedef void type;
};
template <>
struct enable_if_c<false> {};
template <class Cond>
struct enable_if : public enable_if_c<Cond::value> {};
template <typename X>
struct Base { enum { value = 1 }; };
template <typename X, typename Y=Base<X>, typename Z=void>
struct Foo;
template <typename X>
struct Foo<X, Base<X>, void> { enum { value = 0 }; };
template <typename X, typename Y>
struct Foo<X, Y, typename enable_if<Y>::type > { enum { value = 1 }; };
int main(int, char**) {
Foo<int> foo;
}
그러나 GCC (v4.3)로 컴파일하지 못합니다.
foo.cc: In function ‘int main(int, char**)’:
foo.cc:33: error: ambiguous class template instantiation for ‘struct Foo<int, Base<int>, void>’
foo.cc:24: error: candidates are: struct Foo<X, Base<X>, void>
foo.cc:27: error: struct Foo<X, Y, typename enable_if<Y>::type>
foo.cc:33: error: aggregate ‘Foo<int, Base<int>, void> foo’ has incomplete type and cannot be defined
좋아, 그래서 모호하다. 그러나 나는 전문화를 사용할 때 거의 항상 모호함이 될 것으로 기대하지 않았다. 그러나이 오류는 클래스를 사용할 때만 트리거됩니다. enable_if<...>
, 다음과 같은 클래스로 교체하면 아무런 문제가 없습니다.
template <typename X, typename Y>
struct Foo<X, Y, void > { enum { value = 2 }; };
이 클래스는 왜 다른 사람들이 모호함을 유발하지 않습니까? True :: Value를 가진 클래스에서도 두 사람이 동일하지 않습니까? 어쨌든, 내가 잘못하고있는 일에 대한 힌트는 감사합니다.
답변 주셔서 감사합니다, 나의 진짜 문제 (컴파일러가 내 첫 번째 전문화를 선택하도록하기 위해)를 교체하여 해결했습니다. struct Foo<X, Base<X>, void>
~와 함께 struct Foo<X, Base<X>, typename enable_if< Base<X> >::type >
내가 원하는 방식으로 작동하는 것 같습니다.
해결책
질문의 요점은 다음과 같습니다.
template <typename X, typename Y, typename Z>
struct Foo {};
template <typename X>
struct Foo<X, Base<X>, void> {}; // #1
template <typename X, typename Y>
struct Foo<X, Y, typename whatever<Y>::type> {}; // #2
그리고 당신은 그것을 일치 시키려고합니다
Foo<int, Base<int>, void>
분명히, 두 전문화 모두 (첫 번째)와 일치합니다 X = int
, 두 번째 X = int, Y = Base<int>
).
표준에 따르면 섹션 14.5.4에 따르면, 더 일치하는 전문화가있는 경우, 그 중 부분 순서 (14.5.5.2에 정의 된대로)가 구성되고 가장 전문화 된 가장 전문화 된 것들이 사용됩니다. 그러나 귀하의 경우에는 어느 것도 다른 것보다 더 전문적이지 않습니다. (간단히 말해서, 템플릿은 다른 템플릿의 각 유형 매개 변수를 일부 유형으로 바꿀 수 있고 결과적으로 전자의 서명을 얻을 수 있다면 템플릿이 다른 것보다 더 특화되어 있습니다. whatever<Y>::type
그리고 당신은 대체합니다 Y
~와 함께 Base<X>
당신은 얻습니다 whatever<Base<X> >::type
~ 아니다 void
, 즉 처리가 수행되지 않습니다.)
교체하는 경우 #2
~와 함께
template <typename X, typename Y>
struct Foo<X, Y, void > {}; // #3
그런 다음 후보 세트에는 다시 두 템플릿이 모두 포함되어 있지만 #1은 #3보다 더 특화되어 있으며 선택됩니다.
다른 팁
당신은 놓치지 않습니까?
<
상징?
나는 당신이 '<'를 놓치고 있다고 생각합니다. 템플릿은 다음과 같아야합니다.
template< typename T >
struct myStruct
{};
//OR
template< class T >
struct myStruct
{};