Reputation: 1892
My code is:
template<int s>
struct C{
typename std::enable_if<s == 1, int>::type
fun(){std::cout<<"fun1";}
typename std::enable_if<s == 2, int>::type
fun(){std::cout<<"fun2";}
};
int main() {
C<1> c;
c.fun();
}
The compiler said:
error: functions that differ only in their return type cannot be overloaded
my compiler is g++ 4.1.2 if use template<int t = s>
before function, it will warn that is C++11 feature. I want to know how to solve that without using C++11?
Upvotes: 2
Views: 1144
Reputation: 50550
Even if I wouldn't suggest this approach, it follows another possible solution.
I add it as a separate answer only for the sake of curiosity, because I find the other answer most suitable.
Anyway, this one can be of interest because it shows how to use sfinae and function resolution to solve such an issue.
#include<iostream>
#include<type_traits>
template<int s>
struct C {
template<int i>
typename std::enable_if<i == 1>::type
fun(){std::cout<<"fun1"<<std::endl;}
template<int i>
typename std::enable_if<i == 2>::type
fun(){std::cout<<"fun2"<<std::endl;}
void fun() {
fun<s>();
}
};
int main() {
C<1> c1;
c1.fun();
C<2> c2;
c2.fun();
}
Upvotes: 1
Reputation: 50550
If you are able to implement the enable_if
trait, you can rearrange your code as it follows (minimal, complete example) to have it working:
#include<type_traits>
#include<iostream>
struct C {
template<int s>
typename std::enable_if<s == 1, int>::type
fun() { std::cout<<"fun1"; }
template<int s>
typename std::enable_if<s == 2, int>::type
fun() { std::cout<<"fun2"; }
};
int main() {
C c;
c.fun<1>();
}
Your version (almost identical to the following one) won't work even using C++11 features, because it is not a SFINAE resolution of the name fun
:
#include<type_traits>
#include<iostream>
template<int s>
struct C {
typename std::enable_if<s == 1, int>::type
fun() { std::cout<<"fun1"; }
typename std::enable_if<s == 2, int>::type
fun() { std::cout<<"fun2"; }
};
int main() {
C<1> c;
c.fun();
}
If you want the class to be instantiated like C<1>
, simply SFINAE isn't the way to go this time.
Please, note that s
is known at compile time where you decide to use the template class, so you can use it whenever you want.
It follows a possible solution:
#include<type_traits>
#include<iostream>
template<int s>
struct C {
void fun() {
if(s == 1) {
std::cout<<"fun1";
} else if(s == 2) {
std::cout<<"fun2";
}
}
};
int main() {
C<1> c;
c.fun();
}
Another solution would be possible using partial specialization, like the following one:
#include<type_traits>
#include<iostream>
template<int s>
struct C;
template<>
struct C<1> {
void fun() { std::cout<<"fun1"; }
};
template<>
struct C<2> {
void fun() { std::cout<<"fun2"; }
};
int main() {
C<1> c;
c.fun();
}
Which one is the right one for you mainly depends on the actual problem, so I cannot say, but at least now you have several solutions from which to choice.
Upvotes: 3
Reputation: 1677
If you are unable to implement std::enable_if
as mentioned in the comments, I have an alternative shown below. The solution relies on the compiler to optimize out the switch statement, however will still work with a non-optimizing compiler.
#include <iostream>
template <int s>
struct C {
int fun() {
switch (s) {
case 1:
fun1();
break;
case 2:
fun2();
break;
default:
assert(0);
}
}
inline int fun1() { std::cout << "fun1"; }
inline int fun2() { std::cout << "fun2"; }
};
Edit: I had a look through the source code for #include <type_traits>
and found the template for std::enable_if
this is shown below. GPL license applies. From g++
source code, not my own work. I would recommend combining this with skypjacks answer and you most likely solve your problem.
// Primary template.
/// Define a member typedef @c type only if a boolean constant is true.
template<bool, typename _Tp = void>
struct enable_if
{ };
// Partial specialization for true.
template<typename _Tp>
struct enable_if<true, _Tp>
{ typedef _Tp type; };
Upvotes: 0