Reputation: 51685
I tried to use std::enable_if
on a function parameter to trigger SFINAE. Compilation fails with this error:
type_nonsense.cpp:20:5: error: no matching function for call to 'c'
c(SOME::VALUE);
^
type_nonsense.cpp:13:6: note: candidate template ignored: couldn't infer
template argument 'T'
void c(typename std::enable_if<std::is_enum<T>::value, T>::type t) {}
^
1 error generated.
Moving the std::enable_if
to either the return type or to a dummy template parameter works fine. Why?
#include <type_traits>
// Works
template <typename T, typename dummy = typename std::enable_if<std::is_enum<T>::value, T>::type>
void a(T t) {}
// Works
template <typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type b(T t) {}
// Fails to compile
template <typename T>
void c(typename std::enable_if<std::is_enum<T>::value, T>::type t) {}
enum class SOME { VALUE };
int main() {
a(SOME::VALUE);
b(SOME::VALUE);
c(SOME::VALUE);
}
Upvotes: 2
Views: 230
Reputation: 96790
A dependent type in a nested name specifier is a non-deduced context for template argument deduction, and as such cannot be used to determine the type of T
. Placing the std::enable_if
in either the return type or as a default template parameter works because the type of T
isn't being deduced in those contexts.
If you need to place it as a parameter, you can do so like this:
template <typename T>
void c(T t, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr) {}
This works because T
is being deduced by the first argument, not the second.
Upvotes: 5