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?