Warum ist eine Teilklassenvorlagenspezialisierung für eine übereinstimmende Vorlagenklasse mit einer anderen Teilspezialisierung ohne Vorlagenübereinstimmung nicht eindeutig?

8

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_traitmit 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 tempedKlassenvorlage 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 Tund Uauf 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?

Anzeige N.
quelle
Verwandte Frage: stackoverflow.com/q/17412686/9171697
Rin Kaenbyou

Antworten:

1

Die jetzt gelöschte Antwort von @ super hat dies im Grunde richtig gemacht. std::enable_if_t<...>ist nicht voidin 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.

TC
quelle
1
Aber es ist nicht wirklich ein abhängiger Typ, wenn Teilbestellungen durchgeführt werden, oder? Es ist , std::enable_if_t<std::is_same<DummyT, DummyT>::value>wo DummyTeine theoretische-only „synthetisiert“ ist , aber bestimmte Art ( [temp.func.order] / 3 ).
Aschepler
Vielleicht impliziert ein "synthetisierter eindeutiger Typ" auch, dass es zusätzliche Spezialisierungen geben könnte, die diesen Typ verwenden, selbst wenn keine derzeit sichtbaren Spezialisierungen einen Unterschied machen könnten? Aber sagt der Standard das irgendwo?
Aschepler
Möglicherweise fehlt mir Ihr Punkt: Das std_enable_if_t<>bietet eine bevorzugte Teilspezialisierung in der Anweisung trait_t<int, int>::value, so dass es so aussieht, als würde es berücksichtigt void(andernfalls sollte dieser Ausdruck durch Auswahl der Basisvorlage als falsch bewertet werden). Andererseits führt die Aussage trait_t<temped<int>, temped<int>>::valuezu einer Mehrdeutigkeit, obwohl die my_trait<temped<T>, temped<T>, void>erhoffte Teilspezialisierung den voidTyp explizit angibt .
Ad N
Es gibt ein offenes Problem, das mit diesem zusammenhängt: wg21.link/CWG2160 In diesem Fall ist der Abzug jedoch anscheinend in einer Richtung erfolgreich (?), Daher kann ich dieses Beispiel nicht mit diesem Beispiel in Einklang bringen.
Brian
1
Und auf jeden Fall sollte die "echte" Antwort auf die Frage von OP lauten: Der Standard ist diesbezüglich nicht klar. Schreiben Sie also keinen Code wie diesen, bis der Standard dies klarstellt.
Brian
0

es ist, weil

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

beschließt zu annullieren und dann hast du

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

mehrdeutig als wahr oder falsch definiert. Wenn Sie den Typ enable_if ändern, der in bool aufgelöst wird, wird alles gut kompiliert

Yamahari
quelle
1
Das OP fragt, warum es im Rahmen der Teilbestellung der Vorlagenspezialisierung nicht eindeutig ist. Wenn Sie zu wechseln, std::enable_if_t<*, bool>wird der Zweck dadurch zunichte gemacht (da er nicht einmal für die Spezialisierung aktiviert ist).
Rin Kaenbyou