Vincent
Vincent

Reputation: 60381

Return a value depending of type

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

Answers (5)

Luchian Grigore
Luchian Grigore

Reputation: 258618

First off, you can't return anything because the function return type is void.(fixed)

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

Walter
Walter

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

luk32
luk32

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

Eugene Mamin
Eugene Mamin

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

george.zakaryan
george.zakaryan

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

Related Questions