Die Frage mag zu schwer zu beschreiben sein, aber hier ist ein minimales Beispiel:
#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;
}
( auch auf godbolt erhältlich )
Grundsätzlich haben wir eine Basisvorlagenklasse my_trait
mit zwei Typen (und einem Dummy-Typ für Spezialisierungszwecke) mit zwei Teilspezialisierungen:
- Wenn die beiden Typen gleich sind
- Wenn die beiden Typen die Instanziierung der
temped
Klassenvorlage für denselben Typ sind
Naiv hätten wir erwartet, dass die zweite Teilspezialisierung nicht mehrdeutig mit der ersten ist, da sie sich "spezialisierter" anfühlt und die abgeleiteten Typen für T
und U
auf die Basisvorlage stärker einschränkt . Die großen Compiler scheinen jedoch zuzustimmen, dass wir mit unseren Erwartungen falsch lagen: Warum wird es nicht als spezialisierter angesehen?
c++
templates
sfinae
template-specialization
Anzeige N.
quelle
quelle
Antworten:
Die jetzt gelöschte Antwort von @ super hat dies im Grunde richtig gemacht.
std::enable_if_t<...>
ist nichtvoid
in Teilbestellung; als abhängiger Typ kann es im Prinzip etwas völlig Beliebiges sein. Es wird effektiv als ein völlig einzigartiger Typ für Teilbestellzwecke angesehen.Infolge dieser Nichtübereinstimmung schlägt der Abzug während der Teilbestellung in beide Richtungen fehl, und die Spezialisierungen sind nicht eindeutig.
quelle
std::enable_if_t<std::is_same<DummyT, DummyT>::value>
woDummyT
eine theoretische-only „synthetisiert“ ist , aber bestimmte Art ( [temp.func.order] / 3 ).std_enable_if_t<>
bietet eine bevorzugte Teilspezialisierung in der Anweisungtrait_t<int, int>::value
, so dass es so aussieht, als würde es berücksichtigtvoid
(andernfalls sollte dieser Ausdruck durch Auswahl der Basisvorlage als falsch bewertet werden). Andererseits führt die Aussagetrait_t<temped<int>, temped<int>>::value
zu einer Mehrdeutigkeit, obwohl diemy_trait<temped<T>, temped<T>, void>
erhoffte Teilspezialisierung denvoid
Typ explizit angibt .es ist, weil
beschließt zu annullieren und dann hast du
mehrdeutig als wahr oder falsch definiert. Wenn Sie den Typ enable_if ändern, der in bool aufgelöst wird, wird alles gut kompiliert
quelle
std::enable_if_t<*, bool>
wird der Zweck dadurch zunichte gemacht (da er nicht einmal für die Spezialisierung aktiviert ist).