Reputation: 2534
At first I use the enable_if ,the code I write below will not compile,but it seems right in logic,but won't be support by the enable_if implementation in current.
1
2 #include <iostream>
3 using namespace std;
4
5 template<int N>
6 struct S{
7 template<class T>
8 typename enable_if<N==1,T>::type
9 f(T t) {return 1;};
10
11 template<class T>
12 T
13 f(T t) {return 0;};
14 };
15
16 int main() {
17 S<1> s1;
18 S<2> s2;
19 cout << s1.f(99) <<" "<< s2.f(99) << endl;
20 return 0;
21 }
The error message are accurate and problems are pointed out precisely.
enable_if.cc19:20: error: call of overloaded ‘f(int)’ is ambiguous
enable_if.cc:9:3: error: no type named ‘type’ in
‘struct std::enable_if<false, int>’
It seems just the problem of not-well-defined design and can easily be corrected. To deal with it,I can write partial specialized class template:
#include <iostream>
using namespace std;
template<int N> struct S{
template<class T>
T
f(T t) {return 0;};
};
template<> struct S<1>{
template<class T>
T
f(T t) {return 1;};
};
int main() {
S<1> s1;
S<2> s2;
cout << s1.f(99) <<" "<< s2.f(99) << endl;
return 0;
}
But for the cleanses and convenience, what about to enhance the enable_if template to support such new features urged by the wrong code at first?
s1
call f,the more specialized one which return 1 in example can be used.s2
call f,the general one which return 0 will be used,even first one failed. Upvotes: 2
Views: 214
Reputation: 126562
You could workaround the problem by:
enable_if
to be performed at call time.For instance:
#include <type_traits>
template<int N>
struct S
{
template <class T>
typename std::enable_if<N == 1 && std::is_same<T, T>::value, int>::type
f(T t) {return 1;}
template <class T>
typename std::enable_if<N != 1, T>::type
f(T t) {return 0;}
};
Here is a live example.
Upvotes: 2
Reputation: 2767
std::enable_if
is only a tool to choose function overloads. It is implemented as a pure library solution coming from boost. I think the rules for choosing the right overloads are not easy. But asking for changing this in certain cases when enable_if
is involved would make it more complicated. So you best work with partial specialisation and disjunctive enable_if
.
Upvotes: 0
Reputation: 171197
You can still do it without partial specialisation, but:
You must make sure only one of the functions ever exists (otherwise there's ambiguity)
You must make the enable_if
condition depend on the template parameter.
This works:
#include <iostream>
#include <type_traits>
using namespace std;
template <int N>
struct S
{
template <typename T>
typename enable_if<(sizeof(T)>0) && N==1, int>::type
f(T t) { return 1; }
template <typename T>
typename enable_if<(sizeof(T)>0) && N!=1, T>::type
f(T t) { return 0; }
};
int main()
{
S<1> s1;
S<2> s2;
cout << s1.f(99) << " " << s2.f(99) << endl;
}
Upvotes: 0
Reputation: 14327
First of all, I suspect you had a typo in your code. Enable if should be paramterized on T, to compile: typename enable_if<N==1,T>::type
instead of typename enable_if<N==1,int>::type
Just use the second overload with enable if, too, with inverted condition. It works:
#include <iostream>
using namespace std;
template<int N>
struct S{
template<class T>
typename enable_if<N==1,T>::type
f(T t) {return 1;};
template<class T>
typename enable_if<N!=1,T>::type
f(T t) {return 0;};
};
int main() {
S<1> s1;
S<2> s2;
cout << s1.f(99) <<" "<< s2.f(99) << endl;
return 0;
}
Upvotes: 1