Por que uma especialização parcial de modelo de classe em uma classe de modelo correspondente é ambígua com outra especialização parcial sem a correspondência de modelo?

8

A pergunta pode ser muito difícil de descrever na frase do título, mas aqui está um exemplo mínimo:

#include <iostream>
#include <type_traits>

template <class T, class U, class Enabler>
struct my_trait : std::false_type
{};

template <class T, class U>
struct my_trait<T, U, 
                std::enable_if_t<std::is_same<T, U>::value>> : std::true_type
{};

template <class T>
class temped
{};

template <class T>
struct my_trait<temped<T>, temped<T>, void> : std::false_type
{};

template <class T, class U>
using trait_t = my_trait<T, U, void>;

int main()
{
    std::cout << std::boolalpha;
    std::cout << trait_t<int, float>::value << std::endl;   // false
    std::cout << trait_t<int, int>::value << std::endl;     // true

    // Compilation error: Ambiguous
    //std::cout << trait_t<temped<int>, temped<int>>::value << std::endl;
    return 0;    
}

( também disponível no godbolt )

Basicamente, temos uma classe de modelo base que aceita my_traitdois tipos (e um tipo fictício para fins de especialização), com duas especializações parciais:

  • Quando os dois tipos são iguais
  • Quando os dois tipos são instanciação do tempedmodelo de classe para o mesmo tipo

Ingenuamente, esperaríamos que a segunda especialização parcial não fosse ambígua com a primeira, pois parece "mais especializada", colocando mais restrições aos tipos deduzidos para Te Uno modelo base. No entanto, grandes compiladores parecem concordar que estávamos errados com nossas expectativas: por que não é considerado mais especializado?

Anúncio N
fonte
Pergunta relacionada: stackoverflow.com/q/17412686/9171697
Rin Kaenbyou

Respostas:

1

A resposta agora excluída do @ super acertou isso basicamente. std::enable_if_t<...>não está voidem ordem parcial; como um tipo dependente, pode, em princípio, ser algo completamente arbitrário. É efetivamente considerado um tipo completamente exclusivo para fins de pedidos parciais.

Como resultado dessa incompatibilidade, a dedução durante a encomenda parcial falha nas duas direções e as especializações são ambíguas.

TC
fonte
1
Mas não é realmente um tipo dependente ao fazer pedidos parciais, é? É std::enable_if_t<std::is_same<DummyT, DummyT>::value>onde DummyTestá um tipo "sintetizado", mas apenas teórico, específico ( [temp.func.order] / 3 ).
Aschepler #
Talvez um "tipo exclusivo sintetizado" também implique que possa haver especializações adicionais usando esse tipo, mesmo que nenhuma especialização visível no momento possa fazer a diferença? Mas o Padrão diz isso em algum lugar?
aschepler
Eu posso estar perdendo o seu argumento: o std_enable_if_t<>fornece uma especialização parcial preferida na instrução trait_t<int, int>::value, portanto parece que ela é considerada void(caso contrário, parece que essa expressão deve ser avaliada como falsa selecionando o modelo base). Por outro lado, a afirmação trait_t<temped<int>, temped<int>>::valueleva a uma ambiguidade, embora a especialização parcial my_trait<temped<T>, temped<T>, void>que esperávamos fosse mais especializada declare explicitamente o voidtipo.
Ad N
Há um problema em aberto relacionado a este: wg21.link/CWG2160 No entanto, nesse caso, a dedução aparentemente é bem-sucedida em uma direção (?), Portanto, não consigo conciliar esse exemplo com esta.
21719 Brian
1
E, em qualquer caso, a resposta "real" à pergunta do OP deve ser: o padrão não é claro nisso, portanto, não escreva um código como esse até que o padrão o esclareça.
21719 Brian
0

é porque

std::enable_if_t<std::is_same_v<temped<int>, temped<int>> 

resolve anular e então você tem

my_trait<temped<int>, temped<int>, void>::value 

ambigiosamente definido como verdadeiro ou falso. Se você alterar o tipo enable_if resolve, digamos bool, tudo compila bem

Yamahari
fonte
1
O OP está perguntando por que é ambíguo, no contexto da ordenação parcial da especialização de modelos. Se você mudar para std::enable_if_t<*, bool>, isso meio que anula o objetivo (porque nem sequer está habilitado para especialização).
Rin Kaenbyou