7

Ich weiß, es trivial ist zu prüfen, ob ein Typ eine Instanz einer Klasse-Vorlage ist unter TYPE Parametern, wie hier erklärt: How can I check if a type is an instantiation of a given class template?C++ 11: Wie überprüft man, ob ein Typ eine Instanziierung einer gegebenen Klassenvorlage von "heterogenen" NON-TYPE Parametern ist?

Aber ... ist es möglich, ein variadische „is_instantiation_of__ntp < zu haben .. > "(NTP steht für Non-Type Params), die Vorlagen mit einer beliebigen Anzahl von heterogenenNON-TYPE Parametern akzeptieren würde? Zum Beispiel:

template<char*, bool, long, size_t, char> 
struct many_hetero_nontype_params_example {}; 

char HELLO_WORLD[] = "hello world"; 
using ManyHeteroNontypeParamsEx = many_hetero_nontype_params_example<HELLO_WORLD, false, -16, 777, 'x'>; 

Und in der Lage sein, es zu benutzen, wie folgt:

is_instantiation_of__ntp<char*, bool, long, size_t, char, many_hetero_nontype_params_example, ManyHeteroNontypeParamsEx>::value 

Ich weiß, das kann leicht für NON-TYPE Parameterlisten implementiert wird, die 1) „homogen“ sind (Werte des gleichen Typ), oder 2) einige Parameter (so dass eine nicht variadische Lösung praktikabel ist). Ich schrieb sogar einen Testfall diese Sonderfälle (kompiliert mit gcc 4.7.0) zeigt eine bessere Vorstellung davon zu geben, was ich spreche:

namespace test__is_instantiation_of__ 
{ 
    // is_instantiation_of 
    template< template<typename...> class Template, typename T > 
    struct is_instantiation_of : std::false_type {}; 
    template< template<typename...> class Template, typename... Args > 
    struct is_instantiation_of< Template, Template<Args...> > : std::true_type {}; 

    // is_instantiation_of__homogeneous_nontype_params__ 
    template< typename NTP, template<NTP...> class Template, typename T > 
    struct is_instantiation_of__homogeneous_nontype_params__ : std::false_type {}; 
    template< typename NTP, template<NTP...> class Template, NTP... Args > 
    struct is_instantiation_of__homogeneous_nontype_params__< NTP, Template, Template<Args...> > : std::true_type {}; 

    // is_instantiation_of__fixedcount_nontype_params__ 
    template< typename NTP1, typename NTP2, template<NTP1, NTP2> class Template, typename T > 
    struct is_instantiation_of__fixedcount_nontype_params__ : std::false_type {}; 
    template< typename NTP1, typename NTP2, template<NTP1, NTP2> class Template, NTP1 v1, NTP2 v2 > 
    struct is_instantiation_of__fixedcount_nontype_params__< NTP1, NTP2, Template, Template<v1, v2> > : std::true_type {}; 

    // type_params_example 
    template<typename T1, typename T2, typename T3> 
    struct type_params_example {}; 

    // homogeneous_nontype_params_example 
    template<bool B1, bool B2, bool B3, bool B4> 
    struct homogeneous_nontype_params_example {}; 

    // fixedcount_nontype_params_example 
    template<long L, char C> 
    struct fixedcount_nontype_params_example {}; 

    using /*.........*/ TypeParamsEx = /*..........*/ type_params_example<std::string, std::tuple<long, void*>, double>; 
    using HomogenousNontypeParamsEx = homogeneous_nontype_params_example<true, false, true, false>; 
    using FixedCountNontypeParamsEx = fixedcount_nontype_params_example<777, 'x'>; 

    void run() 
    { 
     using std::cout; 
     using std::endl; 

     if (is_instantiation_of<type_params_example, TypeParamsEx>::value) { 
      cout << "[TypeParamsEx] specializes [type_params_example]" << endl; 
     } 
     if (is_instantiation_of<type_params_example, HomogenousNontypeParamsEx>::value) { 
      cout << "[HomogenousNontypeParamsEx] specializes [type_params_example]" << endl; 
     } 
     if (is_instantiation_of<type_params_example, FixedCountNontypeParamsEx>::value) { 
      cout << "[FixedCountNontypeParamsEx] specializes [type_params_example]" << endl; 
     } 

     if (is_instantiation_of__homogeneous_nontype_params__<bool, homogeneous_nontype_params_example, TypeParamsEx>::value) { 
      cout << "[TypeParamsEx] specializes [homogeneous_nontype_params_example]" << endl; 
     } 
     if (is_instantiation_of__homogeneous_nontype_params__<bool, homogeneous_nontype_params_example, HomogenousNontypeParamsEx>::value) { 
      cout << "[HomogenousNontypeParamsEx] specializes [homogeneous_nontype_params_example]" << endl; 
     } 
     if (is_instantiation_of__homogeneous_nontype_params__<bool, homogeneous_nontype_params_example, FixedCountNontypeParamsEx>::value) { 
      cout << "[FixedCountNontypeParamsEx] specializes [homogeneous_nontype_params_example]" << endl; 
     } 

     if (is_instantiation_of__fixedcount_nontype_params__<long, char, fixedcount_nontype_params_example, TypeParamsEx>::value) { 
      cout << "[TypeParamsEx] specializes [fixedcount_nontype_params_example]" << endl; 
     } 
     if (is_instantiation_of__fixedcount_nontype_params__<long, char, fixedcount_nontype_params_example, HomogenousNontypeParamsEx>::value) { 
      cout << "[HomogenousNontypeParamsEx] specializes [fixedcount_nontype_params_example]" << endl; 
     } 
     if (is_instantiation_of__fixedcount_nontype_params__<long, char, fixedcount_nontype_params_example, FixedCountNontypeParamsEx>::value) { 
      cout << "[FixedCountNontypeParamsEx] specializes [fixedcount_nontype_params_example]" << endl; 
     } 
    } 
} 

Wie erwartet, die Ausgabe, die Sie erhalten, ist:

[TypeParamsEx] specializes [type_params_example] 
[HomeogenousNonTypeParamsEx] specializes [homogeneous_nontype_params_example] 
[FixedCountNonTypeParamsEx] specializes [fixedcount_nontype_params_example] 

Das Problem ist keine dieser Vorlagen arbeiten für die many_hetero_nontype_params_example (oben). Beispiel: ein einzelnes variadisches "is_instantiation_of__ntp", das Vorlagen mit einer beliebigen Anzahl von heterogenen Nicht-Typ-Parametern akzeptiert.

Ich denke, wenn Primär-Vorlagen nicht benötigt wurden, um Parameter-Packs am Ende der Template-Parameterliste zu haben, dann wäre dies einfach zu implementieren. Oder wenn es möglich wäre, einen Wrapper-Struct/Nested-Struct-Ansatz zu verwenden. Hier sind meine (nicht) Versuche:

namespace test__is_instantiation_of__nontypes__ 
{ 
    template<char*, bool, long, size_t, char> 
    struct many_hetero_nontype_params_example {}; 

    char HELLO_WORLD[] = "hello world"; 
    using ManyHeteroNontypeParamsEx = many_hetero_nontype_params_example<HELLO_WORLD, false, -16, 777, 'x'>; 

    /* 
    * is_instantiation_of__nontypes_v1__ (version 1) 
    * if uncommented, syntax error as expected ... 
    * error: parameter pack 'NTPs' must be at the end of the template parameter list 
    * error: parameter pack argument 'NTPs ...' must be at the end of the template argument list 
    */ 
    //template< typename... NTPs, template<NTPs...> class Template, typename T > 
    //struct is_instantiation_of__nontypes_v1__ : std::true_type {}; 
    //template< typename... NTPs, template<NTPs...> class Template, NTPs... NonTypeArgs > 
    //struct is_instantiation_of__nontypes_v1__< NTPs..., Template, Template<NonTypeArgs...> > : std::true_type {}; 

    /* 
    * is_instantiation_of__nontypes_v2__ (version 2) 
    * no syntax error (but see instantiation errors below) 
    */ 
    template<typename... NTPs> 
    struct is_instantiation_of__nontypes_v2__ 
    { 
     template< template<NTPs...> class Template, typename T > 
     struct impl : std::false_type {}; 

     template< template<NTPs...> class Template, NTPs... NonTypeArgs > 
     struct impl< Template, Template<NonTypeArgs...> > : std::true_type {}; 
    }; 

    void run() 
    { 
     /* 
     * uncommented since "v1" template has syntax error, but this is how it would be used ... 
     */ 
     //if (is_instantiation_of__nontypes_v1__<char*, bool, long, size_t, char, many_hetero_nontype_params_example, ManyHeteroNontypeParamsEx>::value) { 
     // std::cout << "yes" << std::endl; 
     //} 

     /* 
     * "v2" template has no syntax error, but the following attempt to use it results in these errors ... 
     * 
     * error: type/value mismatch at argument 1 in template parameter list for 'template<class ... NTPs> template<template<template<NTPs ...<anonymous> > class Template, class T> template<class ... NTPs> template<NTPs ...<anonymous> > class Template, class T> struct is_instantiation_of__nontypes_v2__<NTPs>::impl' 
     * error: expected a template of type 'template<class ... NTPs> template<NTPs ...<anonymous> > class Template', got 'template<char* <anonymous>, bool <anonymous>, long int <anonymous>, long unsigned int <anonymous>, char <anonymous> > struct many_hetero_nontype_params_example' 
     */ 
     //if (is_instantiation_of__nontypes_v2__<char*, bool, long, size_t, char>::impl<many_hetero_nontype_params_example, ManyHeteroNontypeParamsEx>::value) { 
     // std::cout << "yes" << std::endl; 
     //} 
    } 
} 

...

Ist eine variadische Lösung für diese überhaupt möglich?

Vielen Dank im Voraus.

+0

Ich glaube, ich habe Ihre Frage in meiner ursprünglichen Antwort missverstanden, tut mir leid. Löscht es und liefert eine bessere Antwort. –

+0

Ihre ursprüngliche Antwort erklärte, warum es keine offensichtliche Lösung für dieses Problem gibt, wie zum Beispiel die Deklaration eines Parameterpakets "typename ... ScalarTypes", um dann die Vorlagenvorlage "Vorlage Klasse TheTemplate" zu deklarieren Parameterliste. Andere mögliche Lösungen werden nicht behandelt, z. B. der Versuch is_instantiation_of__nontypes_v2__, den ich gepostet habe, der eine umschließende Struktur zum Deklarieren des Parameter-Packs für den Template-Template-Parameter verwendet, der in der Parameterliste der geschachtelten Struktur deklariert ist. – etherice

+0

Wenn Sie erklärt hätten, warum dieser "v2" -Versuch nicht funktioniert (speziell die gcc-Fehler beim Versuch, ihn zu benutzen), wäre ich ziemlich überzeugt, dass dies nicht möglich ist und die Antwort akzeptiert hätte. Aber es wäre schön, das sicher zu wissen. Danke, dass du dir das angeschaut hast. – etherice

Antwort

5

Sie haben wahrscheinlich einen Compilerfehler gefunden. Ich habe versucht, dies zu einem einfacheren Beispiel zu reduzieren:

#include <iostream> 

template<bool, char> struct A { }; 

template<typename... Ts> 
struct test 
{ 
    template<typename T> 
    struct impl : std::false_type {}; 

    template<Ts... Args> 
    struct impl<A<Args...>> : std::true_type {}; 
}; 

int main() 
{ 
    using IA = A<false, 'x'>; 
    std::cout << ((test<bool, char>::impl<IA>::value) ? "Y" : "N"); 
} 

GCC 4.7.2 kompiliert diese, aber das kompilierte Programm prints the wrong output (N). Auf der anderen Seite, Clang 3.2 bekommt das Recht, und das kompilierte Programm prints the correct output (Y).

Hier ist eine leicht modifizierte Version des oben genannten Programms, in dem die test Klassenvorlage Ihre is_instantiation_of__nontypes_v2__ Klassenvorlage sehr ähnlich:

#include <iostream> 

template<bool, char> struct A {}; 

template<typename... Ts> 
struct test 
{ 
    template<template<Ts...> class TT, typename T> 
    struct impl : std::false_type {}; 

    template<template<Ts...> class TT, Ts... Args> 
    struct impl<TT, TT<Args...>> : std::true_type {}; 
}; 

int main() 
{ 
    using IA = A<false, 'x'>; 
    std::cout << ((test<bool, char>::impl<A, IA>::value) ? "Y" : "N"); 
} 

Während Clang kompiliert diese und das kompilierte Programm druckt die richtige Ausgabe (Y), GCC emittiert die folgenden Kompilierungsfehler:

expected a template of type 'template<class ... Ts> template<Ts ...<anonymous> > class TT' , got 'template<bool <anonymous>, char <anonymous> > struct A' .

Es ist wie GCC sieht nicht erkennen, dass die erste Vorlage Template-Parameter eine Vorlage Argument Liste haben sollten gegeben durch die Erweiterung von Ts. Daher scheint mir dies ein Fehler des GCC zu sein.

+0

Richtig bezüglich des Fehlens des "literal_type ..." -Argumentpakets, das dies erschwert. Es könnte jedoch immer noch möglich sein, wenn es eine Möglichkeit gäbe, "typename ... ScalarTypes" in der Template-Parameterliste zu deklarieren und dann die Template-Vorlage als "template class TheTemplate" ... zu definieren Problem ist, dass das Parameter-Pack am Ende der Liste stehen muss (nachdem TheTemplate deklariert wurde). Sie können meine "gescheiterten Versuche" am Ende des Beitrags sehen ... Ich bin auf der Suche nach einer ähnlichen Technik, die tatsächlich funktioniert. "is_instantiation_of__nontypes_v2__" kommt mir nahe, denke ich. – etherice

+0

@etherice: Ich habe versucht, ein wenig darauf in der letzten Bearbeitung meiner Antwort zu kommentieren. –

+0

Diese Regel (die Sie ermutigt haben) gilt für den Versuch "v1", aber ** scheint nicht zutreffend für den Versuch "v2". "typename ... NTPs" ist in der Template-Parameter-Liste der umgebenden Struktur deklariert, nicht die geschachtelte Struktur. Wie ich schon sagte, es kompiliert, aber sehen Sie die gcc-Fehler, wenn ich versuche, es zu verwenden. Können Sie den Fehler erklären? – etherice