2017-08-17 8 views
4

Der folgende Code mit dem Fehler zu kompilieren schlägt fehl template template argument has different template parameters than its corresponding template template parameter:Vorlage Vorlage Argumente Uneinheitliche mit Abgeleitete Vorlage Argumente

#include <tuple> 
#include <vector> 
#include <string> 
#include <iostream> 

template<template<typename, typename> class Blah, typename KeyType, typename ValueType> 
void print_tuploid(const Blah<KeyType, ValueType>& tup) { 
    std::cout << "first value: " << std::get<0>(tup) << " second value: " << std::get<1>(tup) << std::endl; 
} 

int main() { 
    auto stuff = std::make_tuple(1, 2); 
    print_tuploid(stuff); 
} 

Die ursprüngliche Absicht hinter diesem Code ist irrelevant, an dieser Stelle ich nur versuchen, mich, warum dies zu verstehen gilt als ungültig.

Wenn ich den Anruf zu std::make_tuple in std::make_pair ändere, kompiliert der Code und läuft korrekt, was zu der Annahme führt, dass etwas Seltsames passiert, das spezifisch für std::tuple ist.

ich ursprünglich dachte, dass std::tuple könnte einige zusätzliche haben, Verzug geraten, schablonen Argumente, die ich nicht bewusst war, denn wenn ich die Definition von print_tuploid der folgenden ändern, wird der Code sowohl kompilieren für std::make_tuple und std::make_pair:

template<template<typename...> class Blah, typename KeyType, typename ValueType> 
void print_tuploid(const Blah<KeyType, ValueType>& tup) { 
    std::cout << "first value: " << std::get<0>(tup) << " second value: " << std::get<1>(tup) << std::endl; 
} 

Aber als ich versuchte, die abgeleitete Art von stuff mit dem folgenden Code auskippen:

#include <tuple> 

template<typename T> 
class TypePrinter; 

int main() { 
    auto stuff = std::make_tuple(1, 2); 
    TypePrinter<decltype(stuff)> error; 
} 

Es wird berichtet: implicit instantiation of undefined template 'TypePrinter<std::__1::tuple<int, int> >', was zu der Annahme führt, dass dies nicht der Fall ist.

Auch, als eine Nebenfrage, warum tritt Referenzzusammenbruch in diesem Kontext nicht auf? Der folgende Code wird auch als ungültig betrachtet:

#include <iostream> 

template<template<typename, typename> class Blah, typename KeyType, typename ValueType> 
void print_tuploid(Blah<KeyType, ValueType>&& tup) { 
    std::cout << "first value: " << std::get<0>(tup) << " second value: " << std::get<1>(tup) << std::endl; 
} 

int main() { 
    auto stuff = std::make_pair(1, 2); 
    print_tuploid(stuff); 
} 

Geben Sie den Fehler: no known conversion from 'std::__1::pair<int, int>' to 'pair<int, int> &&' for 1st argument.

Im Grunde versuche ich nur mein Template-Wissen zu erweitern, indem ich verstehe, was genau hier vor sich geht. Entschuldigung für die lange Post und danke im Voraus für jede Anleitung, die jemand zur Verfügung stellen kann.

+0

Momentan kann nicht zu einem vollständigen Post expandiert werden, aber die Übereinstimmung der genauen Template-Parameter mit den Parameterpaketen wird als falsch angesehen. Es gibt ein Papier, aber ich vergesse, wenn es in 17 akzeptiert wurde. – user975989

+0

Referenz-Kollabieren tritt für einen Parameter wie 'T &&' auf - es ist eine Lvalue-Referenz, wenn 'T' als lvalue-Referenz abgeleitet wird, und rvalue-Referenz andernfalls. 'Blah ' kann unmöglich zu einem Lvalue-Referenztyp abgeleitet werden - es ist eindeutig ein Klassentyp. –

Antwort

4

Das Problem mit der Funktion ist, dass es mit einer Vorlagenklasse übereinstimmt, die genau 2 Argumente benötigt. In Wirklichkeit hat std::tuple die Vorlagensignatur von template <typename...>. Der Unterschied liegt darin, dass tuple eine beliebige Menge von Template-Parametern nimmt, während Ihre Funktion erwartet.

std::pair funktioniert gut, weil die Vorlage Signatur template <typename, typename> ist, die genau übereinstimmt.

Es gibt einen Vorschlag, obwohl ich nicht in der Lage bin, die neueste Version zu finden, die diese Art von Spezialisierung ermöglicht. Es scheint in C++ 17 oder zumindest etwas Ähnliches übergegangen zu sein, da die cppreference-Seite für Template-Template-Parameter dies als ein gültiges Beispiel betrachtet. Der Vorschlag, den ich gefunden habe, ist here.

Der Grund, warum Ihre zweite Version std::pair nicht akzeptiert, ist, weil sie eine Rvalue-Referenz erwartet. Sobald Sie einen (teilweise) spezialisierten Typ haben, können Sie && nicht als Weiterleitungsreferenz behandeln.

Verwandte Themen