Pergunta

Eu tenho o seguinte código (desculpe pelo grande pedaço de código, mas não pude mais reduzi -lo)

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;
}

Mas não consegue compilar com o GCC (v4.3) com

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

OK, então é ambíguo. Mas eu não esperava que fosse um problema, pois, ao usar a especialização, quase sempre será alguma ambiguidade. No entanto, este erro é acionado apenas ao usar a classe com enable_if<...>, se eu substituí -lo por uma classe como a seguinte, não há problema.

template <typename X, typename Y>
struct Foo<X, Y, void > { enum { value = 2 }; };

Por que essa classe não causa ambiguidade enquanto os outros fazem? Os dois não são a mesma coisa para as aulas com um valor verdadeiro ::? De qualquer forma, quaisquer dicas sobre o que estou fazendo de errado são apreciadas.

Obrigado pelas respostas, meu verdadeiro problema (para fazer com que o compilador selecione minha primeira especialização) foi resolvido substituindo struct Foo<X, Base<X>, void> com struct Foo<X, Base<X>, typename enable_if< Base<X> >::type > o que parece funcionar da maneira que eu quero.

Foi útil?

Solução

A essência da sua pergunta é que você tem:

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

E você está tentando combinar com isso

Foo<int, Base<int>, void>

Obviamente, ambas as especializações correspondem (a primeira com X = int, o segundo com X = int, Y = Base<int>).

De acordo com o padrão, a seção 14.5.4, se houver mais especializações correspondentes, uma ordem parcial (conforme definida em 14.5.5.2) é construída e a mais especializada é usada. No seu caso, no entanto, nenhum deles é mais especializado que o outro. (Simplificando, um modelo é mais especializado que outro, se você pode substituir cada parâmetro de tipo do último modelo por algum tipo e em resultado, obtenha a assinatura do primeiro. Além disso, se você tiver whatever<Y>::type e você substitui Y com Base<X> você fica whatever<Base<X> >::type não void, ou seja, não há processamento realizado.)

Se você substituir #2 com

template <typename X, typename Y>
struct Foo<X, Y, void > {};                        // #3

Em seguida, o conjunto do candidato contém novamente os dois modelos, no entanto, o número 1 é mais especializado do que o #3 e, como tal, é selecionado.

Outras dicas

Você não está perdendo um

<

símbolo?

Eu acho que você está perdendo um '<', um modelo deve parecer:

template< typename T >
struct myStruct
{};

//OR

template< class T >
struct myStruct
{};
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top