C++, как определить std :: result_of <f (r)>, который может обрабатывать r, является недействительным

Когда я использую

std::result_of<F(R)>

нравится:

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

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

Поскольку R - это другой тип вывода функции, поэтому R может быть void, в этой ситуации будут:

error: invalid parameter type ‘void’.

Так что вопрос в том, как обрабатывать как R, так и void и нет?

coliru.stacked-crooked.com/a/d9d9b859ca90e928
Piotr Skotnicki 10.09.2018 10:45

Может ли OP предоставить фактический фрагмент, который не работает, но, как ожидается, будет работать. Я считаю, что правки, исправляющие этот пример, были интерпретацией редактора. Task<void(void)> работает

luk32 10.09.2018 10:45

@ luk32 ты поставил R=void(void), а Then даже не вызвал

Piotr Skotnicki 10.09.2018 10:49

@ luk32 Вам действительно нужно использовать Then. Конечно, Task можно создать с любыми параметрами шаблона. Хотя вы правы в том, что использование Task в возвращаемом типе Then не имело смысла ни при какой версии этого вопроса.

Max Langhof 10.09.2018 10:49

@PiotrSkotnicki Это очень четкое решение, ОГРОМНОЕ спасибо

D.pz 10.09.2018 10:51

@MaxLanghof Да, я видел это после примера Петра. Спасибо. Тем не менее, оригинальный MCVE был бы неплохим.

luk32 10.09.2018 10:51

@PiotrSkotnicki Пожалуйста, не публикуйте ответы в комментариях.

Max Langhof 10.09.2018 10:51
1
7
195
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Опция 1

На базе СФИНАЭ:

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 {};
    }
};

ДЕМО

Вариант # 2

Частичная специализация шаблона класса:

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 {};
    }
};

ДЕМО 2

Вариант # 3

Диспетчеризация тегов:

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>{});
    }
};

ДЕМО 3

Другие вопросы по теме