Using std::enable_if with anonymous type parameters
c++, c++11, enable-if, sfinae, templates
Solution
However, my intention is to get some more details why it does not work if I use it with anonymous type parameters.
Default values do not participate in overload resolution, thus you are actually redefining the same function.
Let's simplify your example:
template<typename = int>
void f() {}
template<typename = void>
void f() {}
int main() {
f<>();
}
The code above does not compile, for it couldn't know what version of `f` you want to invoke.
In your case, if I invoke `foo` as `foo<void, void>`, I've almost the same problem. The compiler cannot guess what's my intention and the fact that the second parameter has a default value doesn't mean that you can't pass in a different type.
Because of that, the code is ill-formed and the compiler correctly gives you an error.
As a side note, you can still have it working without using the `std::enable_if_t` in the return type. As an example:
#include <type_traits>
#include <iostream>
template <typename T, std::enable_if_t<!std::is_integral<T>::value>* = nullptr>
T foo() { std::cout << "non-integral" << std::endl; return T(); }
template <typename T, std::enable_if_t<std::is_integral<T>::value>* = nullptr>
T foo() { std::cout << "integral" << std::endl; return T(); }
int main() {
foo<float>();
foo<int>();
}
While I tried to figure out what was the (wrong) assumption of the OP and explain why it can be the case, @T.C. correctly pointed the attention out to the actual reason in the comments to this answer. It's worth to quote his comment to add more details to the answer:
It's not overload resolution; it's declaration matching. There are no two overloads in the first place for any ambiguity to arise. It's two redefinition errors: the function template, and the default template argument.
Problem
I try to use `std::enable_if` with an unused and unnamed type parameter, in order to not distort the `return` type. However, the following code does not compile. ``` #include <iostream> template <typename T, typename = std::enable_if_t<!std::is_integral<T>::value>> T foo() { std::cout << "non-integral" << std::endl; return T(); } template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> T foo() { std::cout << "integral" << std::endl; return T(); } int main() { foo<float>(); foo<int>(); } ``` The compiler says: ``` 7:3: error: redefinition of 'template<class T, class> T foo()' 4:3: note: 'template<class T, class> T foo()' previously declared here In function 'int main()': 11:12: error: no matching function for call to 'foo()' 11:12: note: candidate is: 4:3: note: template<class T, class> T foo() 4:3: note: template argument deduction/substitution failed: ``` What is the problem here? How do I have to change the code to get it compile? The text book "Discovering Modern C++" explicitly encourages the use of `std::enable_if` with anonymous type parameters. EDIT: I know that it works if I put `std::enable_if` into the return type. However, my intention is to get some more details why it does not work if I use it with anonymous type parameters. As I said, my text book encourages the variant using anonymous type parameters, so I am wondering why my code does not compile.