2017-06-02 3 views
8

Betrachten Sie den folgenden Code ein:Deduktion Führung und variadische Vorlagen

#include <tuple> 
#include <iostream> 

template <class T> 
struct custom_wrapper 
{ 
    template <class Arg> 
    custom_wrapper(Arg arg): data(arg) {} 
    T data; 
}; 

template <class Arg> 
custom_wrapper(Arg arg) -> custom_wrapper<Arg>; 

template <class... T> 
struct custom_tuple 
{ 
    template <class... Args> 
    custom_tuple(Args... args): data(args...) {} 
    std::tuple<T...> data; 
}; 

template <class... Args> 
custom_tuple(Args... args) -> custom_tuple<Args...>; 

int main(int argc, char* argv[]) 
{ 
    custom_wrapper<int> w1(42); // OK 
    custom_wrapper w2(42);  // OK 
    custom_tuple<int> t1(42); // OK 
    custom_tuple t2(42);   // Fails 
    return 0; 
} 

Die Zeile, die den folgenden Fehler unter g ++ 7 nicht zurück:

variadic_deduction_guide.cpp: In instantiation of 'custom_tuple<T>::custom_tuple(Args ...) [with Args = {int}; T = {}]': 
variadic_deduction_guide.cpp:31:23: required from here 
variadic_deduction_guide.cpp:19:45: error: no matching function for call to 'std::tuple<>::tuple(int&)' 
    custom_tuple(Args... args): data(args...) {} 

Ist das normal oder ist, dass ein Compiler Fehler ?

Antwort

3

Dies ist gcc bug 80871. Was folgt, ist eine Erklärung dafür, warum der Code wohlgeformt ist (und es ist richtig zu entscheiden, dass t2 ein custom_tuple<int> ist).


Der Prozess, herauszufinden, was mit

custom_tuple t2(42); 

im Grunde eine Reihe von Funktionen beinhaltet zu tun zu synthetisieren und auf ihnen die Überladungsauflösung durchführen. Die entsprechenden Kandidaten sind die synthetisierten Funktionen aus dem einem Konstruktor und der Abzug Führung:

template <class... T, class... Args> 
custom_tuple<T...> foo(Args...);  // the constructor 

template <class... Args> 
custom_tuple<Args...> foo(Args...); // the deduction guide 

Von diesem Punkt ist es ein auf der Grundlage Ihrer Interpretation Ihre eigenen Abenteuer wählen, was ein „nachlauf Parameter Pack“ wird nach [temp.arg.explicit]/3:

Ein nachfolgendes Template-Parameterpaket, das nicht anderweitig abgeleitet ist, wird auf eine leere Sequenz von Template-Argumenten zurückgeführt. Wenn alle Vorlagenargumente abgeleitet werden können, können sie alle weggelassen werden; In diesem Fall kann auch die leere Vorlagenargumentliste <> selbst weggelassen werden.

T... schleppt nicht

Dieser Fall ist einfach. Wir haben nur einen brauchbaren Kandidaten (weil T... nicht ableitbar ist) - der Deduktionsleitkandidat. Wir leiten Args... als {int} ab, also enden wir mit custom_tuple<int>.

T... nachläuft

Beide gcc und Klirren tatsächlich Abzug betrachten für den Konstruktor erfolgreich zu sein. Also gehen wir zu den Tiebreaker in [over.match.best]:

diese Definitionen gegeben, eine tragfähige Funktion F1 ist definiert als ein besser Funktion als eine andere tragfähige Funktion F2 wenn [...]

  • F1 sein und F2 sind Funktionsvorlagenspezialisierungen, und die Funktionsvorlage für F1 ist spezialisierter als die Vorlage für F2 gemäß den Teilordnungsregeln, die in [temp.func.order] beschrieben sind, oder, falls nicht,
  • F1 wird aus einem Deduction-Guide ([over.match.class.educt]) generiert und F2 ist nicht, oder, wenn nicht das, [...]

Für die Zwecke der partiellen Ordnung, sind die relevant types Parameter solche, die nur entsprechen funktionieren, und wir sind zu ignore unused template parameters erlaubt, so dass die anderen weder Funktionsvorlage gilt als spezialisierter als.

Dies lässt uns einfach den Deduktionsführer bevorzugen, der der einfachste Schritt dieses ganzen Prozesses war. Wir leiten Args... als {int} ab, also enden wir mit custom_tuple<int>.


Wie auch immer, custom_tuple<int> ist die richtige Entscheidung.

+0

Hmm, GCC und Clang Stamm nicht einverstanden auf OP-Code, und ich bin hier nicht wirklich überzeugt. Erstens, ist "T" "nach"? (Das ist ein ziemlich unbestimmter Begriff.) Zweitens, können Sie demonstrieren, wie der Konstruktor spezialisierter ist als der Deduktionsleitfaden? –

+0

@ T.C. Aber cool zu sehen, wie Clang mit Deduktions-Guides arbeitet! Das muss ziemlich neu sein. – Barry

+0

Der Kontext hier ist ein Funktionsaufruf, also ["die verwendeten Typen \ [für die partielle Sortierung \] sind diejenigen Funktionsparameter, für die der Funktionsaufruf Argumente hat"] (https://timsong-cpp.github.io/cppwp /temp.deduct.partial#3.1). Und für partielle Bestellzwecke kann [ein Vorlagenparameter ohne einen Wert bleiben, vorausgesetzt, er wird nicht in den Typen verwendet, die für die teilweise Bestellung verwendet werden] (https://timsong-cpp.github.io/cppwp/temp.deduct. Teil # 12) und 'T ...' ist nicht. Also genau wie ist einer spezialisierter als der andere? In welche Richtung scheitert der Abzug und wie? –

Verwandte Themen