2016-08-26 22 views
8

To jest kolejne pytanie do Detecting constexpr with SFINAE.SFINAE constexpr ze std :: get

Chcę wykryć, czy element krotki (lub czegokolwiek, co można użyć z std::get) jest constexpr. Więc napisałem następujące pomocników podobne do tego, co dał Xeo:

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(...); 

Teraz mój kierowca testowy kod:

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'; 
} 

to jednak zawsze drukuje się false dla mnie! Aby sprawdzić, które z jakiegoś powodu fałszywego przeciążenie nie jest zawsze o nazwie, ja wykomentowane fałszywego przeciążenia i pojawia się błąd kompilatora:

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)>;

Jednak wiem, że mogę zadzwonić std::get<N>(arg) i uzyskać wartość constexpr :

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; 
} 

To kompiluje się dobrze.

  • Dlaczego funkcja kontrolna nie wykrywa prawidłowo elementu constexpr-ness?
  • Jak to naprawić?

Testowałem to z Clang 3.8.0 na Ubuntu 16.04.

edit:

Jako dalsze badania w oparciu o odpowiedź Sam starałem postać:

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

ten pozbywa się operatora przecinek, który całkowicie GCC 5.4.0 kompiluje dobrze , ale Clang 3.8.0 wciąż narzeka. Co ciekawe, Clang podkreśla, że ​​sama arg nie jest constexpr.

Dlaczego ten problem nadal występuje? Jakie są reguły dotyczące argumentów funkcji constexpr?

+2

Problem polega na tym, że parametr 'arg' nie jest' constexpr' ... – Jarod42

+1

(Aby nieco rozszerzyć to, co myślę @ Jarod42 znaczy: 'arg' jest parametrem funkcji nigdy nie jest traktowane jako wyrażenie ciągłe, nawet jeśli argument, który podajesz do funkcji, jest wyrażeniem stałym.) – dyp

+0

Jak wykryłbym, jeśli wynik wywołania funkcji byłby constexpr, jeśli ta metoda nie działa? Oczywiście mogę użyć tej krotki jako wartości constexpr przez skonstruowanie obiektu 'a_val'. – helloworld922

Odpowiedz

3

To wygląda na kompilator.

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

gcc nie skompilować to:

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

Ale po szczypanie to nieco, mam oczekiwanych rezultatów z 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'; 
} 

Skutkuje:

is constexpr? 1 

Uwaga: przecinki nie były dozwolone w wyrażeniach stałych przed C++ 11. Może być coś, co pozostało z tamtej ery ...

+0

Próbowałem twojej poprawki w clangu 3.8.0 i to nie działa, ale robi to z GCC 5.4.0. Co ciekawe, część, której clang podkreśla jako niebędącą constexpr, nie jest operatorem przecinka, ale fakt, że 'arg' nie jest constexpr (testowałem to przez usunięcie operatora przecinka). – helloworld922

+0

Wymagane zachowanie różni się w Twojej wersji. SFINAE nie ma zastosowania do wyprowadzonych typów zwrotu; SFINAE jest tylko w bezpośrednim kontekście, podczas gdy dedukcja typu powrotu wymaga raczej głębokiego utworzenia szablonu funkcji. – dyp

+0

Co ciekawe, @dyp, wynikiem końcowym jest zamierzony wynik. Parametr inny niż constexpr nie spowodował błędu kompilacji, ale oczekiwanego domyślnego szablonu. Wydaje mi się, że typ powrotu funkcji szablonu jest wyprowadzany w momencie deklaracji, a następnie normalnie uczestniczy w rozdzielczości SFINAE. –

Powiązane problemy