views:

91

answers:

2

Hello all,

I have structure for storing callback function like this:

template<class T>
struct CommandGlobal : CommandBase
{
    typedef boost::function<T ()> Command;
    Command comm;

    virtual T Execute() const
    {
        if(comm)
            return comm();
        return NULL;
    }
};

Seems like it should work fine except when T is void because the Execute function wants to return a value..

What is the best solution to this problem?

Thanks!

+6  A: 

This answer is based off this fun-fact: In a function returning void, you can return any expression of which the type is void.

So the simple solution is:

virtual T Execute() const
{
    if (comm) // boolean logic change, typo in OP?
        return comm();
    else
        return static_cast<T>(NULL);
}

When T = void, the last return statement is equivalent to return;.


However, I feel this is bad design. Is NULL meaningful for every T? I don't think so. I would throw an exception:

virtual T Execute() const
{
    if (comm)
        return comm();
    else
        throw std::runtime_error("No function!")
}

However, this is done automatically by Boost, so your code becomes the much cleaner:

virtual T Execute() const
{
    return comm();
}

You could then add additional functionality, such as:

bool empty(void) const
{
    return !comm; // or return comm.empty() if you're the explicit type
}

So the user can check if it can be called prior to calling it. Of course at this point, unless your class has additional functionality you've left out for the sake of the question, I see no reason not to just use boost::function in the first place.

GMan
@GMan: is that C-style cast I am seeing there?
akira
@akira: Gone. :) Just a temporary before I touched it up a bit.
GMan
+1  A: 

If it's just the return statement, this should do the trick:

virtual T Execute() const
{
    if(comm)
        return comm();
    return T();
}

If there's more to it, specialize the template for void.

sbi
Which assumes that `T` is default constructible.
Georg Fritzsche
@Georg: That's true. However, some presumptions you have to make and the one creating a default object when you don't have one seems less harmful than the original code's assumption that `T` can be constructed from `NULL` (which fails badly if `T` is a `std::string`). If all else fails, you can still make a specialization that creates the object in some different way or put the code creating the default return value into a policy.
sbi
Didn't mean to imply it isn't an option, i just thought its not obvious to everyone and would better be pointed out :)
Georg Fritzsche