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_trait
dois 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
temped
modelo 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 T
e U
no modelo base. No entanto, grandes compiladores parecem concordar que estávamos errados com nossas expectativas: por que não é considerado mais especializado?
c++
templates
sfinae
template-specialization
Anúncio N
fonte
fonte
Respostas:
A resposta agora excluída do @ super acertou isso basicamente.
std::enable_if_t<...>
não estávoid
em 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.
fonte
std::enable_if_t<std::is_same<DummyT, DummyT>::value>
ondeDummyT
está um tipo "sintetizado", mas apenas teórico, específico ( [temp.func.order] / 3 ).std_enable_if_t<>
fornece uma especialização parcial preferida na instruçãotrait_t<int, int>::value
, portanto parece que ela é consideradavoid
(caso contrário, parece que essa expressão deve ser avaliada como falsa selecionando o modelo base). Por outro lado, a afirmaçãotrait_t<temped<int>, temped<int>>::value
leva a uma ambiguidade, embora a especialização parcialmy_trait<temped<T>, temped<T>, void>
que esperávamos fosse mais especializada declare explicitamente ovoid
tipo.é porque
resolve anular e então você tem
ambigiosamente definido como verdadeiro ou falso. Se você alterar o tipo enable_if resolve, digamos bool, tudo compila bem
fonte
std::enable_if_t<*, bool>
, isso meio que anula o objetivo (porque nem sequer está habilitado para especialização).