2014-01-26 8 views
8

Mit variablen Templates in C++ 14 kommen (und Clang bereits unterstützt sie) und einen Vorschlag für Standard is_same_v und ebenfalls Züge geben, dachte ich, neue Art Züge in der Lage zu machen, wie wäre ordentlich folgt:Kann ich eine variable Vorlage verwenden, um eine andere variable Vorlage zu deklarieren?

template<typename T> 
constexpr bool is_const_and_volatile{std::is_const_v<T> && std::is_volatile_v<T>}; 

Leider führt dies zu Fehlern entsprechen den folgenden SSCCE (this one enthält alles, was weiter unten erwähnt):

#include <type_traits> 

template<typename T> 
constexpr bool is_pointer{std::is_pointer<T>::value}; 

template<typename T> 
constexpr bool foo{is_pointer<T>}; 

int main() { 
    //foo<int *>; 
} 

Mit der Linie in main kommentierte Spieße Clang aus dem folgenden:

warning: variable is_pointer<type-parameter-0-0> has internal linkage but is not defined

Es mir definiert sieht (beachten Sie, dass T-int * in foo funktioniert ändern). Uncommenting die Linie in mainfoo diese zu instanziiert gibt (wieder T-int * funktioniert gut):

error: constexpr variable foo<int *> must be initialized by a constant expression

jedoch foo mit der folgenden alten Syntax ersetzt verursacht beiden Instanzen funktionieren:

constexpr bool foo{std::is_pointer<T>::value}; 

Gibt es etwas, das mir an variablen Vorlagen fehlt? Gibt es eine Möglichkeit, neue variable Vorlagen mit zu bauen, oder bin ich gezwungen, die ältere Syntax zu verwenden, um neue zu erstellen und nur den syntaktischen Zucker zu genießen, wenn Sie sie für anderen Code verwenden?

+2

Haben Sie explizite Instanziierung versucht? Luc Danton entdeckt [einen Fehler im Zusammenhang mit impliziten Instanziierung vor kurzem ..] (http://stackoverflow.com/a/21234048/420683) – dyp

+0

(scheint mit expliziter Instantiierung "arbeiten": http: //coliru.stacked-crooked. com/a/e16d249679a71d0c) – dyp

+0

@dyp, Ok, aber Hinzufügen von einem für 'bool *' in Ihrem Beispiel [gibt immer noch den Linker-Fehler] (http://coliru.stacked-crooked.com/a/990bc676207518a2), ​​leider, Ganz zu schweigen von der Tatsache, dass ich es nicht explizit für jeden Typ instantiieren kann. – chris

Antwort

0

Die folgende scheint zu funktionieren:

#include <type_traits> 
#include <iostream> 

template<typename T> 
struct test { 
    static constexpr bool is_pointer{std::is_pointer<T>::value}; 
}; 

template<typename T> 
constexpr bool test<T>::is_pointer; 

template<typename T> 
constexpr bool foo{test<T>::is_pointer}; 

int main() { 
    std::cout << foo<bool>; 
    std::cout << foo<bool*>; 
} 

Live Example

Obwohl es die gleiche Warnung Procs, wenn in einem constexpr Kontext verwendet, damit ich es nehme wirklich schließlich nicht funktioniert.

// Fail 
template<typename T> 
typename std::enable_if<foo<T>, void>::type bar() 
{ 
} 

int main() { 
    bar<bool*>(); 
} 

main.cpp:21:5: error: no matching function for call to 'bar' 

    bar<bool*>(); 

    ^~~~~~~~~~ 

main.cpp:16:45: note: candidate template ignored: substitution failure [with T = bool *]: non-type template argument is not a constant expression 

typename std::enable_if<foo<T>, void>::type bar() 

Es beschwert sich nicht mehr, wenn Sie foo eine explizite Art geben:

template<typename T> 
typename std::enable_if<foo<bool*>, void>::type bar() 
{ 
} 

Oder nur test<T>::is_pointer direkt verwenden:

template<typename T> 
typename std::enable_if<test<T>::is_pointer, void>::type bar() 
{ 
} 
Verwandte Themen