Ich habe mit variablen C ++ 0x-Vorlagen experimentiert, als ich auf dieses Problem gestoßen bin:
template < typename ...Args >
struct identities
{
typedef Args type; //compile error: "parameter packs not expanded with '...'
};
//The following code just shows an example of potential use, but has no relation
//with what I am actually trying to achieve.
template < typename T >
struct convert_in_tuple
{
typedef std::tuple< typename T::type... > type;
};
typedef convert_in_tuple< identities< int, float > >::type int_float_tuple;
GCC 4.5.0 gibt eine Fehlermeldung aus, wenn ich versuche, das Vorlagenparameterpaket einzugeben.
Grundsätzlich möchte ich das Parameterpaket in einem typedef "speichern", ohne es zu entpacken. Ist es möglich? Wenn nicht, gibt es einen Grund, warum dies nicht zulässig ist?
c++
templates
c++11
variadic-templates
Luc Touraille
quelle
quelle
typedef typename convert_in_tuple<Args...>::type type;
, oder spielt das keine Rolle?variadic_typedef
und wie sie mit dem obigen Code interagiert. Stellen Sie sich nun eine Liste von Typen vor, die jeweils an a übergeben werden,convert_in_tuple
und wie sie mit dem obigen Code interagieren. Wenn Sie einige Indirektionsebenen einrichten, führt die Behandlung des Containers und des Inhalts als austauschbar zu Problemen.Ich denke, der Grund, warum es nicht erlaubt ist, ist, dass es chaotisch wäre und man es umgehen kann. Sie müssen die Abhängigkeitsinversion verwenden und die Struktur, die das Parameterpaket in einer Factory-Vorlage speichert, in die Lage versetzen, dieses Parameterpaket auf eine andere Vorlage anzuwenden.
Etwas in der Art von:
template < typename ...Args > struct identities { template < template<typename ...> class T > struct apply { typedef T<Args...> type; }; }; template < template<template<typename ...> class> class T > struct convert_in_tuple { typedef typename T<std::tuple>::type type; }; typedef convert_in_tuple< identities< int, float >::apply >::type int_float_tuple;
quelle
typename T
inclass T
und ändernconvert_in_tuple
Parameter einen Template - Template - Template - Parameter zu sein:template < template< template < typename ... > class > class T > struct convert_in_tuple {...}
(!).typename
durchclass
fühlt sich etwas zweifelhaft an, da im Entwurf steht "Es gibt keinen semantischen Unterschied zwischenclass
undtemplate
in einem Vorlagenparameter .". Könnten Sie diesen neuen Code ausprobieren?class
und nichttypename
(weil ein Vorlagentyp zwangsläufig eine Klasse und kein Typ ist).class
und gibttypename
, aber genau darüber (in §14.1.1) erlaubt die Syntax nur dasclass
Schlüsselwort in der Parameterdeklaration der Vorlagenvorlage. Auch wenn dies inkonsistent erscheinen kann, denke ich, dass die Begründung, wie ich bereits sagte, darin besteht, dass ein Vorlagenvorlagenparameter kein Typ sein kann (z. B. nichtint
oder nichtbool
), weshalb das Komitee möglicherweise entschieden hat, dass die Verwendung vontypename
sein soll irreführend. Wie auch immer, kommen wir zurück zum Thema :)!Ich fand Ben Voigts Idee sehr nützlich für meine eigenen Bemühungen. Ich habe es leicht modifiziert, um es allgemein zu machen und nicht nur Tupel. Für die Leser hier mag es eine offensichtliche Modifikation sein, aber es kann sich lohnen, Folgendes zu zeigen:
template <template <class ... Args> class T, class ... Args> struct TypeWithList { typedef T<Args...> type; }; template <template <class ... Args> class T, class ... Args> struct TypeWithList<T, VariadicTypedef<Args...>> { typedef typename TypeWithList<T, Args...>::type type; };
Der Name TypeWithList ergibt sich aus der Tatsache, dass der Typ jetzt mit einer vorherigen Liste instanziiert wird.
quelle
Dies ist eine Variation von GManNickGs ordentlichem Teilspezialisierungstrick. Keine Delegierung, und Sie erhalten mehr Typensicherheit, wenn Sie die Verwendung Ihrer variadic_typedef-Struktur benötigen.
#include <tuple> template<typename... Args> struct variadic_typedef {}; template<typename... Args> struct convert_in_tuple { //Leaving this empty will cause the compiler //to complain if you try to access a "type" member. //You may also be able to do something like: //static_assert(std::is_same<>::value, "blah") //if you know something about the types. }; template<typename... Args> struct convert_in_tuple< variadic_typedef<Args...> > { //use Args normally typedef std::tuple<Args...> type; }; typedef variadic_typedef<int, float> myTypes; typedef convert_in_tuple<myTypes>::type int_float_tuple; //compiles //typedef convert_in_tuple<int, float>::type int_float_tuple; //doesn't compile int main() {}
quelle
variadic_typedef
zu verwenden, eine Funktion sein sollte. Daher würde ich sagen, dass diese Antwort eher eine Verschlechterung als eine Verfeinerung ist ...variadic_typedef
for entfernenconvert_in_tuple
- lassen Sie es sich nehmentemplate<typename Pack> struct convert_in_tuple {};
und dann spezialisierentemplate<template<typename...>class Pack, typename...Args> struct convert_in_tuple<Pack<Args...>> { typedef std::tuple<Args> type; }
- jetzt kann jedes Variardic Pack einem zugeordnet werdentuple
.