2014-01-29 3 views
14

Ich möchte überprüfen, ob eine Vorlage mit einem gegebenen Satz von Argumenten spezialisiert werden kann. Hier ist die Version für Vorlagen nur 1 Argument akzeptieren:Überprüfen Sie, ob eine gültige Template-Spezialisierung

#include <iostream> 

template<template<typename...> class C, typename T> 
struct is_valid_specialization { 
    typedef struct { char _; } yes; 
    typedef struct { yes _[2]; } no; 

    template<template<typename...> class D, typename U> 
    static yes test(D<U>*); 
    template<template<typename...> class D, typename U> 
    static no test(...); 

    constexpr static bool value = (sizeof(test<C, T>(0)) == sizeof(yes)); 
}; 

template<typename T> 
struct Test1 { }; 

template<typename T1, typename T2> 
struct Test2 { }; 

template<typename...> 
struct TestV { }; 

int main() { 
    std::cout << "Test1<T>: " << is_valid_specialization<Test1, int>::value << std::endl; 
    std::cout << "Test2<T>: " << is_valid_specialization<Test2, int>::value << std::endl; 
    std::cout << "TestV<T>: " << is_valid_specialization<TestV, int>::value << std::endl; 
} 

Diese does the job für Vorlagen nur ein einziges Argument akzeptieren, aber natürlich möchte ich in der Lage sein, dies auch mit mehreren Argumenten zu verwenden, so dass ich versuchte, dies:

template<template<typename...> class C, typename... T> 
struct is_valid_specialization { 
    typedef struct { char _; } yes; 
    typedef struct { yes _[2]; } no; 

    template<template<typename...> class D, typename... U> 
    static yes test(D<U...>*); 
    template<template<typename...> class D, typename... U> 
    static no test(...); 

    constexpr static bool value = (sizeof(test<C, T...>(0)) == sizeof(yes)); 
}; 

Jetzt ist dies, wo die Dinge komisch werden, denn jetzt .

Gibt es etwas, das mir fehlt? Was ist so völlig anders zwischen diesen beiden Versionen? Gibt es einen anderen Weg, dies zu erreichen?

EDIT:
ich sowohl für Clang und GCC einen Fehlerbericht eingereicht haben

+0

Wenn ich nicht weiß, was mit solchen Dingen falsch ist, kommentiere ich die Fallback-Funktion aus ('no test (...)') und sehe, was die Fehlermeldung sagt. In diesem Fall beschwert sich der Compiler darüber, dass zu viele D-Argumente zu viele Vorlagenargumente enthalten. Beats me ... – jrok

+2

Übrigens testen diese nur, ob die Argumente mit der Template-Parameterliste übereinstimmen, nicht ob eine vollständige Instanziierung der Vorlage tatsächlich erfolgreich wäre. Letzteres ist unmöglich. –

Antwort

9

Die folgende einfacher ist und funktioniert:

template<template<typename...> class C, typename... T> 
struct is_valid_specialization { 
    typedef struct { char _; } yes; 
    typedef struct { yes _[2]; } no; 

    template<template<typename...> class D> 
    static yes test(D<T...>*); 
    template<template<typename...> class D> 
    static no test(...); 

    constexpr static bool value = (sizeof(test<C>(0)) == sizeof(yes)); 
}; 

Live example

+0

Ich sah "der Abzug ist zu kompliziert", bevor Sie bearbeitet :) Ich sehe keinen Grund, warum es unmöglich wäre. – jrok

+0

@jrok Deshalb habe ich es gelöscht. Ich weiß nicht, was genau das Problem verursacht. –

+0

@jrok Ja, das habe ich auch gesehen. Also im Grunde ist es nur ein Manko von GCC und Clang (kann VS nicht testen) im Moment? –

1

Die Anzahl der Template-Parameter akzeptiert durch den Funktionstest (U ...) ist immer noch nicht bekannt, auch wenn Sie den ersten T ... Parameter. Weitere U ... Template-Parameter können aus den Funktionsparametern abgeleitet werden. Da der Funktionsparameter (0) nicht hilft, die Größe von U zu erraten, wird die erste Template-Funktion nicht instanziiert. Es ist wichtig zu beachten, dass der Vorlagenparameter D auch eine beliebige Anzahl von Parametern annehmen kann. Der Compiler sollte keine Annahmen machen.

GCC und Clang haben Recht.