SFINAE constexpr with std :: get

This is the next question for Detecting constexpr using SFINAE .

I want to determine if a tuple element (or something that can be used with std::get ) is constexpr. So I wrote the following helpers, similar to what Xeo gave:

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

Now my test driver code is:

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

However, this always outputs false to me! To verify that for some reason a false overload is not always called, I commented on a false overload and received a compiler error:

Note: candidate template is ignored: replacement 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)>;

However, I know that I can call std::get<N>(arg) and get the value of 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; } 

This compiles just fine.

  • Why doesn't the validation function detect constexprness correctly?
  • How to fix it?

I tested this with Clang 3.8.0 on Ubuntu 16.04.

change

As an additional test based on Sam's answer, I tried the form:

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

This completely eliminates the comma operator, which GCC 5.4.0 compiles just fine, but Clang 3.8.0 still complains. Interestingly, Klang emphasizes that arg itself is not constexpr.

Why is this problem still not resolved? What are the rules for constexpr function arguments?

+8
c ++ sfinae c ++ 14 constexpr
source share
1 answer

This seems like a compiler issue.

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

gcc cannot compile this:

tC: 8: 61: error: template argument 1 is invalid automatic check (const T & arg) → sfinae_true <(std :: get (arg), N)>;

But after a little adjustment, I get the expected results with 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'; } 

This leads to:

 is constexpr? 1 

Please note that commas are not allowed in pre-C ++ 11 constant expressions. Maybe something remains from that era ...

+3
source share

All Articles