D.pz
D.pz

Reputation: 161

c++ how to define a std::result_of<F(R)> that can handle R is void

When i am using

std::result_of<F(R)>

like this:

template<typename R, typename... Args>
class Task
{
    //...

    template<typename F>
    auto Then(F&& f) -> Task<typename std::result_of<F(R)>::type(Args...)>
    {  
        //... 
    }    
}; 

Since R is another function's output type, so R may be void, in this situation, there will be:

error: invalid parameter type ‘void’.

So the question is how to handle both R is void and is not?

Upvotes: 1

Views: 272

Answers (1)

Piotr Skotnicki
Piotr Skotnicki

Reputation: 48527

Option #1

SFINAE-based:

template <typename F>
class Task;

template <typename R, typename... Args>
class Task<R(Args...)>
{
public:
    template <typename F, typename Ret = R>
    auto Then(F&& f)
        -> typename std::enable_if<!std::is_void<Ret>::value, Task<typename std::result_of<F(Ret)>::type(Args...)>>::type
    {
        return {};
    }

    template <typename F, typename Ret = R>
    auto Then(F&& f)
        -> typename std::enable_if<std::is_void<Ret>::value, Task<typename std::result_of<F()>::type(Args...)>>::type
    {
        return {};
    }
};

DEMO

Option #2

Partial-specialization of the class template:

template <typename F>
class Task;

template <typename R, typename... Args>
class Task<R(Args...)>
{
public:
    template <typename F>
    auto Then(F&& f)
        -> Task<typename std::result_of<F(R)>::type(Args...)>
    {
        return {};
    }
};

template <typename... Args>
class Task<void(Args...)>
{
public:
    template <typename F>
    auto Then(F&& f)
        -> Task<typename std::result_of<F()>::type(Args...)>
    {
        return {};
    }
};

DEMO 2

Option #3

Tag-dispatching:

template <typename F>
class Task;

template <typename R, typename... Args>
class Task<R(Args...)>
{    
private:
    template <typename F>
    auto ThenImpl(F&& f, std::true_type)
        -> Task<typename std::result_of<F()>::type(Args...)>
    {
        return {};
    }

    template <typename F, typename Ret = R>
    auto ThenImpl(F&& f, std::false_type)
        -> Task<typename std::result_of<F(Ret)>::type(Args...)>
    {
        return {};
    }

public:
    template <typename F>
    auto Then(F&& f)
        -> decltype(ThenImpl(std::forward<F>(f), std::is_void<R>{}))
    {
        return ThenImpl(std::forward<F>(f), std::is_void<R>{});
    }
};

DEMO 3

Upvotes: 5

Related Questions