Minimal program:
#include <stdio.h>
#include <type_traits>
template<typename S, typename T>
int foo(typename T::type s) {
return 1;
}
template<typename S, typename T>
int foo(S s) {
return 2;
}
int main(int argc, char* argv[]) {
int x = 3;
printf("%d\n", foo<int, std::enable_if<true, int>>(x));
return 0;
}
output:
1
Why doesn't this give a compile error? When the template code is generated, wouldn't the functions int foo(typename T::type search)
and int foo(S& search)
have the same signature?
If you change the template function signatures a little bit, it still works (as I would expect given the example above):
template<typename S, typename T>
void foo(typename T::type s) {
printf("a\n");
}
template<typename S, typename T>
void foo(S s) {
printf("b\n");
}
Yet this doesn't and yet the only difference is that one has an int signature and the other is defined by the first template parameter.
template<typename S, typename T>
void foo(typename T::type s) {
printf("a\n");
}
template<typename S, typename T>
void foo(int s) {
printf("b\n");
}
Compiler error (Clang):
test.cpp:26:2: error: call to 'foo' is ambiguous
foo<std::enable_if<true, int>>(3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(typename T::type s) {
^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(int s) {
^
1 error generated.
I'm using code similar to this for a project I'm working on and I'm afraid that there's a subtly to the language that I'm not understanding that will cause some undefined behavior in certain cases. I should also mention that it does compile on both Clang and in VS11 so I don't think it's just a compiler bug.
Edit: Corrected second case (typo); added error message from Clang.
Edit #2: For those of you that asked what T::type means.
From http://en.cppreference.com/w/cpp/types/enable_if:
template< bool B, class T = void > struct enable_if;
If B is true, std::enable_if has a public member typedef type, equal to T; otherwise, there is no member typedef.
enable_if is a struct. Basically, if the expression evaluated in the first template parameter of enable_if is true (and in the case of my examples above, it is), then then there will be a public member type
that has the same type as the second template parameter.
In the case of enable_if<true, int>
, enable_if::type has a type of int.