std::get
does not seem to be SFINAE-friendly, as shown by the following test case:
template <class T, class C>
auto foo(C &c) -> decltype(std::get<T>(c)) {
return std::get<T>(c);
}
template <class>
void foo(...) { }
int main() {
std::tuple<int> tuple{42};
foo<int>(tuple); // Works fine
foo<double>(tuple); // Crashes and burns
}
The goal is to divert the second call to foo
towards the second overload. In practice, libstdc++ gives:
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.0/../../../../include/c++/6.3.0/tuple:1290:14: fatal error: no matching function for call to '__get_helper2'
{ return std::__get_helper2<_Tp>(__t); }
^~~~~~~~~~~~~~~~~~~~~~~
libc++ is more direct, with a straight static_assert
detonation:
/usr/include/c++/v1/tuple:801:5: fatal error: static_assert failed "type not found in type list"
static_assert ( value != -1, "type not found in type list" );
^ ~~~~~~~~~~~
I would really like not to implement onion layers checking whether C
is an std::tuple
specialization, and looking for T
inside its parameters...
Is there a reason for std::get
not to be SFINAE-friendly? Is there a better workaround than what is outlined above?
I've found something about std::tuple_element
, but not std::get
.
foo
.T
isdouble
.C
is that tuple type. Substitution succeeded! – Pseudohermaphroditismstd::get
was SFINAE-friendly (i.e. let itself out of the overload set for an invalid call). Hence my question. – Pewextern void foo(); template<typename T=decltype(foo())> void bar() { }
-- this will compile just fine, despite the compiler not having the foggiest what's insidefoo()
. Substitution does not involve actually generating the code. – Pseudohermaphroditism-> decltype(std::get<T>(c))
is not. – Pewstd::get
's template parameter being a class, its return type is explicit, rather than beingauto
, as would be the case for a tuple index constant. So,decltype()
is happy.template< class T, class... Types > constexpr T& get(tuple<Types...>& t);
-- game over. – Pseudohermaphroditismstd::get
could very well be fitted with, for example,std::enable_if
so it doesn't accept invalid arguments, instead of blowing up after substitution. That's the whole point of SFINAE. – Pew