2016-08-26 6 views
8

Dies ist eine Follow-up-Frage zu Detecting constexpr with SFINAE.SFINAE constexpr mit Std :: get

Ich möchte erkennen, ob ein Element eines Tupel (oder irgendetwas, das mit std::get verwendet werden kann) constexpr ist. Also schrieb ich die folgenden Helfer ähnlich dem, was Xeo gab:

template<size_t> struct sfinae_true : std::true_type{}; 

template<size_t N, class T> 
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>; 

template<size_t N, class> 
std::false_type check(...); 

Jetzt ist mein Testfahrer Code:

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr; 
    std::cout << "is constexpr? " << is_cexpr::value << '\n'; 
} 

Dies ist jedoch immer druckt false für mich! Um zu überprüfen, dass aus irgendeinem Grunde ist die falsche Überlastung nicht immer genannt wird, ich aus der falschen Überlastung kommentiert und den Compiler-Fehler:

note: candidate template ignored: substitution failure [with N = 0, T = const std ::tuple]: non-type template argument is not a constant expression
auto check(const T& arg) -> sfinae_true<(std::get(arg),0)>;

jedoch

, ich weiß, dass ich std::get<N>(arg) anrufen und einen constexpr Wert erhalten :

template<size_t N> 
class A{}; 

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    A<std::get<0>(arg)> a_val; 
} 

Das kompiliert gerade fein.

  • Warum erkennt die Prüffunktion den Kontextzugriff nicht richtig?
  • Wie behebe ich das?

Ich testete dies mit Clang 3.8.0 auf Ubuntu 16.04.

edit:

Als weiterer Test auf Sams Antwort basiert, ich die Form versucht:

template<size_t N, class T> 
auto check(const T& arg) 
{ 
    return sfinae_true<(std::get<N>(arg)*0)>(); 
} 

Dieses vollständig aus dem Komma-Operator entledigt, die GCC kompiliert 5.4.0 just fine , aber Clang 3.8.0 beschwert sich immer noch über. Interessanterweise hebt Clang hervor, dass arg selbst kein Constexpr ist.

Warum ist das Problem immer noch? Wie lauten die Regeln für die constexpr-Funktionsargumente?

+2

Problem ist, dass 'arg' Parameter ist nicht 'constexpr' ... – Jarod42

+1

(Um etwas zu erweitern, was ich denke @ Jarod42 bedeutet:' arg' ist ein Funktionsparameter ist nie als konstanter Ausdruck betrachtet, auch wenn das Argument, das Sie der Funktion übergeben, ein konstanter Ausdruck ist.) – dyp

+0

Wie würde ich erkennen, ob das Ergebnis eines Funktionsaufrufs conexpr wäre, wenn diese Methode nicht funktioniert? Natürlich kann ich das Tupel als conexpr-Wert verwenden, indem ich das 'a_val'-Objekt konstruiere. – helloworld922

Antwort

3

Dies sieht wie ein Compiler-Problem aus.

template<size_t N, class T> 
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>; 

gcc versagt diese kompilieren:

t.C:8:61: error: template argument 1 is invalid auto check(const T& arg) -> sfinae_true<(std::get(arg),N)>;

Aber nach diesem etwas zwicken, bekomme ich die erwarteten Ergebnisse mit gcc 6.1.1:

#include <tuple> 
#include <type_traits> 
#include <iostream> 

template<size_t> struct sfinae_true : std::true_type{}; 

template<size_t N, class T> 
auto check(const T& arg) 
{ 
    return sfinae_true<(std::get<N>(arg),N)>(); 
} 

template<size_t N, class> 
std::false_type check(...); 

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr; 
    std::cout << "is constexpr? " << is_cexpr::value << '\n'; 
} 

Daraus ergibt sich:

is constexpr? 1 

Beachten Sie, dass Kommas weren 't erlaubt in konstanten Ausdrücken vor C++ 11. Könnte etwas von dieser Ära übrig bleiben ...

+0

Ich habe versucht, Ihre zwicken in clang 3.8.0 und es funktioniert nicht, aber es mit GCC 5.4.0. Interessanterweise ist der Teil, der als nicht-consExpr hervorgeht, nicht der Komma-Operator, sondern die Tatsache, dass "arg" nicht-consExpr ist (ich habe dies getestet, indem ich den Komma-Operator entfernt habe). – helloworld922

+0

Das mandatierte Verhalten unterscheidet sich in Ihrer Version. SFINAE gilt nicht für abgeleitete Rückgabetypen; SFINAE ist nur im unmittelbaren Kontext, während die Rückgabetypableitung eine ziemlich tiefe Instanziierung der Funktionsvorlage erfordert. – dyp

+0

Interessanterweise ist @Dyp das Endergebnis das beabsichtigte Ergebnis. Ein non-constexpr-Parameter führte nicht zu einem Kompilierungsfehler, sondern zu der erwarteten Standardvorlage. Es sieht für mich so aus, als ob der Rückgabetyp der Template-Funktion zur Deklarationszeit abgeleitet wird und dann normal an der SFINAE-Auflösung teilnimmt. –

Verwandte Themen