2016-04-15 13 views
0

Kann ich enable_if (oder gibt es eine alternative Technik) mit Template-Variablen verwenden? z.B.variable Vorlagen und std :: enable_if

typedef float Float; 
typedef double Double; 

template<class T> 
constexpr Bool IsFloat = std::is_same_v<T, Float>; 

template<class T> 
constexpr Bool IsDouble = std::is_same_v<T, Double>; 

template<class T> 
constexpr Bool IsFloatingPoint = IsFloat<T> || IsDouble<T>; 

template<class T> 
using EnableIfFloatingPoint = std::enable_if_t<IsFloatingPoint<T>>; 

template 
< 
    class T, 
    typename = EnableIfFloatingPoint<T> 
> 
constexpr T Pi = T(3.1415926535897932384626433832795); 

Visual Studio gibt mir einen Fehler Compiler „zu wenige Argumente Vorlage“ zu sagen, wenn ich versuche Pi<float> zu verwenden, zum Beispiel.

+0

Wenig verwirrt, warum Sie "IsFloatingPoint" in diesem Beitrag nicht eingeschlossen haben. – WhozCraig

+0

@WhozCraig, denn jetzt gibt es doppelt so viel Code, und das meiste ist irrelevant. – user673679

+0

Das Konzept von SFINAE ist für variable Templates nicht sinnvoll, da sie weder überladen noch teilweise spezialisiert sein können. – Brian

Antwort

2

Als Erstes würde ich die Verwendung von std::is_floating_point empfehlen, anstatt einen eigenen Gleitkomma-Erkennungsmechanismus zu verwenden. Darüber hinaus können Sie das _v-Suffix anstelle von ::value ab C++ 17 verwenden. Wie in einigen Kommentaren erwähnt, ist die Verwendung von SFINAE selbst bei variablen Vorlagen nicht sehr sinnvoll, aber Sie könnten Ihre Lösung erreichen, nur Gleitkommatypen zu erlauben, den Wert Pi zu übernehmen, indem Sie versuchen, den Wert Pi zu übernehmen um die Variablenvorlage auf den Typ std::enable_if_t< std::is_floating_point<T>::value, T> zu setzen, der natürlich nur einen abgeleiteten Typ hat, wenn die Bedingung erfüllt ist.

template<class T> 
using EnableIfFloatingPoint = std::enable_if_t<std::is_floating_point<T>::value, T>; 

template<class T> 
constexpr T Pi = EnableIfFloatingPoint<T>(3.1415926535897932384626433832795); 

Pi<T> für integrale Typen T einfach zu kompilieren fehlschlagen, weil EnableIfFloatingPoint<T> nicht jede Art abgeleitet, aber ich würde dieses SFINAE nicht in Betracht ziehen.

Eine bessere Lösung wäre eine constexpr Funktionsvorlage mit einer entsprechenden static_assert Nachricht, die verifiziert, dass die Vorlage mit dem "richtigen" Typ instanziiert wurde.

template<class T> 
constexpr T Pi() 
{ 
    using is_fp = std::is_floating_point<T>; 
    static_assert(is_fp::value, "Pi must be instantiated with floating point types."); 
    return T{3.1415926535897932384626433832795}; 
}