Reputation: 1241
Suppose we have a class:
template <class Type>
class A
{
public:
void function1(float a, Type b);
void function1(float a, float b);
};
Now instantiate the class like this:
A<int> a;
It's fine, this class will have 2 overloaded functions with these parameters: (float a, int b); (float a, float b);
But when you instantiate the class like this:
A<float> a;
You get compile error:
member function redeclared.
So, depending on the type of Type, I wan't (or don't want) the compiler to define a function, something like this:
template <class Type>
class A
{
public:
void function1(float a, Type b);
#if Type != float
void function1(float a, float b);
#endif
};
But, of course, the syntax above doesn't work. Is it possible to perform such a task in C++? If possible, please provide an example.
Upvotes: 9
Views: 5133
Reputation: 52117
You could use template specialization:
template <class Type>
class A {
public:
void function1(float a, Type b) {
}
void function1(float a, float b) {
}
};
template <>
class A<float> {
public:
void function1(float a, float b) {
}
};
// ...
A<int> a_int;
a_int.function1(23.4f, 1);
a_int.function1(23.4f, 56.7f);
A<float> a_float;
a_float.function1(23.4f, 56.7f);
If you have a large number of common functions, you could do something like this:
class AImp {
public:
void function1(float a, float b) {
}
void function1(float a, double b) {
}
void function1(float a, const std::string& b) {
}
// Other functions...
};
template <class Type>
class A : public AImp {
public:
void function1(float a, Type b) {
}
using AImp::function1;
};
template <>
class A<float> : public AImp {
};
// ...
A<int> a_int;
a_int.function1(23.4f, 1);
a_int.function1(23.4f, 56.7f);
a_int.function1(23.4f, 56.7);
a_int.function1(23.4f, "bar");
A<float> a_float;
a_float.function1(23.4f, 56.7f);
a_float.function1(23.4f, 56.7);
a_float.function1(23.4f, "bar");
Upvotes: 8
Reputation: 279305
Use SFINAE:
#include <iostream>
#include <type_traits>
template <typename Type>
struct Foo {
template <typename T = Type>
void function1(float a, float b, typename std::enable_if<!std::is_same<T, float>::value>::type *c = 0) {
std::cout << "float\n";
}
void function1(float a, Type b) {
std::cout << "type\n";
}
};
int main() {
Foo<float> f;
f.function1(1, 1);
f.function1(1.0f,1.0f);
Foo<int> g;
g.function1(1,1);
g.function1(1.0f,1.0f);
g.function1(1.0,1.0); // warning!
}
Output:
type
type
type
float
type
You'll need C++11 mode, to allow the default template parameter in a function template. And also to get enable_if
and is_same
, although you could get enable_if
from Boost instead.
The "warning!" is because with your original code g.function1(1.0,1.0);
was ambiguous. Now the the non-template overload is preferred. You can make it ambiguous again by doing
template <typename T = Type>
void function1(float a, Type b, typename std::enable_if<true>::type *c = 0) {
std::cout << "type\n";
}
Upvotes: 2
Reputation: 34588
You can use some C++11
std::enable_if
:
template <class Type>
class A
{
public:
template<typename t = Type,
typename std::enable_if<!std::is_same<t, float>::value, int>::type = 0>
void function1(float a, Type b) {
}
void function1(float a, float b) {
}
};
Upvotes: 9