Reputation: 60381
Consider the following example
template<class Type = void> class MyClass
{
public:
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (/* SOMETHING */) ? (_x) : (_y);
}
protected:
double _x;
static const double _y;
};
What could be the /* SOMETHING */
condition ?
I want to return _x
if the template parameter is void, and return _y
if not. How to do that ?
Upvotes: 3
Views: 529
Reputation: 258618
First off, you can't return anything because the function return type is (fixed)void
.
Second, you can specialize that function to act differently when Type
is void
:
template<class Type> class MyClass
{
public:
double getValue()
{
return _y;
}
protected:
double _x;
static const double _y;
};
template<>
inline double MyClass<void>::getValue()
{
return _x;
}
Upvotes: 12
Reputation: 45444
Using SFINAE ensures that all the work is done by the compiler, while other options using typeid
, dynamic_cast
etc, require some run-time costs, which are completely unnecessary (since all the information is available at compile time). In fact, these are extremely bad examples for when best to use such methods.
A possible SFINAE solution is
template<class Type = void> class MyClass
{
public:
typename std::enable_if< std::is_void<Type>::value, double>::type
getValue() { return _x; }
typename std::enable_if<!std::is_void<Type>::value, double>::type
getValue() { return _y; }
protected:
double _x;
static const double _y;
};
Upvotes: 0
Reputation: 16070
For now main problem is that you defined getValue()
as returning void
.
But let's skip that.
A function definition in C++ needs to be well defined. This means it needs to have immutable return type and argument list and a name. (There is couple of more attributes I believe but it is not that important here).
You can overload function so you have a couple of definitions with differing argument lists, however the returning type must be the same for all functions with the same name. You can get different returning type if you use templates, and the returning type would be a template argument.
Now to handle different types, there are two ways I believe. One is use templates and specializations.
You could define getValue()
as template<T> double getValue();
and then use different specializations to handle different branches of your original getValue
. In your example it would be:
//default case
template<typename T> double MyClass<T>::getValue() { return _y; }
//void case
template<> double MyClass<void>::getValue() { return _x; }
The second option is to use RTTI mechanism which allows to determine types of objects in run-time. The the code could like almost exactly like yours. E.g.
double getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return (typeid(Type) == typeid(void)) ? (_x) : (_y);
}
It all depends whether you can determine Type during compilation or not. The RTTI approach has its drawbacks. If you ever wanted to handle more types RTTI allows you to do it by modifying one function while template approach you would need to add another specialization. I guess its up to one's preferences which path to take... and template are quite nicer when it comes to design.
Edit: Oopsies ... I missed that your class is templatized by the Type
. So that should practically remove RTTI apporach out of question. I will leave the answer anyways if anyone ever comes here drawn by the sole title, as I believe it is still a valid way to do it.
Upvotes: 0
Reputation: 749
You could write using SFINAE:
template<typename Type = void>
class MyClass
{
public:
std::enable_if<std::is_same<Type, void>::value, decltype(_x)> getValue()
{
// if "Type == void" return _x, if "Type != void" return _y
return _x;
}
std::enable_if<!(std::is_same<Type, void>::value), decltype(_y)> getValue()
{
return _y;
}
protected:
double _x;
static const double _y;
};
Upvotes: 4
Reputation: 980
You can use dynamic casts to test for types. Dynamic casts return null pointers if the cast is made to a different type;
Here's an example.
SomeClass* somePointer = NULL;
somePointer = dynamic_cast<SomeClass*>(someOtherPointer);
if (somePointer)
{
// *someOtherPointer is of type SomeClass
}
else
{
// *someOtherPointer is not of type SomeClass
}
Upvotes: 0