Skip to content

Instantly share code, notes, and snippets.

@jgreitemann
Last active May 16, 2016 09:53
Show Gist options
  • Save jgreitemann/17fd2de9994db3929e7a3442e9decf12 to your computer and use it in GitHub Desktop.
Save jgreitemann/17fd2de9994db3929e7a3442e9decf12 to your computer and use it in GitHub Desktop.
SFINAE
#include <iostream>
#include <type_traits>
using namespace std;
template <typename...> using void_t = void;
template <typename T, typename = void>
struct has_foo : false_type {};
template <typename T>
struct has_foo<T, void_t<decltype(&T::foo)>> : true_type {};
struct bar {
void foo() {
cout << "foo" << endl;
}
};
struct baz {
void fool() {
cout << "fool" << endl;
}
};
template <typename T>
void call_foo(T t) {
static_assert(has_foo<T>::value,
"T does not have member function foo");
t.foo();
}
int main() {
cout << boolalpha
<< has_foo<bar>::value << endl
<< has_foo<baz>::value << endl;
call_foo(bar());
}

SFINAE (Substitution failure is not an error) refers to a situation where template substitution is artifically forced to fail if a testable condition is not met. This can be useful in conjunction with type traits. In the present code, a custom type trait is used to detect if a template parameter type has a member function named foo. The general definition of has_foo extends the false_type base class whereas a partial template specialization extends true_type. The specialization takes place in the second, unnamed, template parameter which otherwise defaults to void. In the specialization, this is replaced by the void_t type defined beforehand. This also just aliases void but accepts unnamed (variadic) template parameters. Now, in the template specialization of has_foo, a function pointer type to T::foo is passed as a template parameter to void_t. Despite void_t not doing anything with it, this will cause the template substitution to fail if and only if T does not have a member function foo. This failure, however, is not considered an error! It merely causes the compiler not to apply the template specialization (extending true_type) for types not sporting a foo member function but to fall back to the generic template (extending false_type). This trait may be used to impose and test for required properties of template parameter types using static_assert.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment