Параметр функции типа void - PullRequest
3 голосов
/ 07 марта 2020

Можно ли сделать следующий псевдокод компиляцией без определения явной специализации GetValue<void>?

template <class Increment = void>
inline int GetValue(const Increment & inc = {})
{
    if constexpr (std::is_same_v<Increment, void>)
    {
        return 25;
    }
    else
    {
        return 25 + inc;
    }
}

int main()
{
    std::cout << GetValue(1) << std::endl; //compiles
    std::cout << GetValue() << std::endl;  //does not compile
}

В этом псевдокоде я передаю в качестве параметра GetValue либо значение, на которое я увеличиваю 25 константа или некоторое значение, которое указывает «абсолютно ничего». И не совсем понятно, что это за «абсолютно ничто» и как его представить, если параметр типа void не компилируется.

Если я определяю поддельный тип, такой как

struct Nothing {};

это, вероятно, выглядит ничем, но не как «абсолютно ничто».

Ответы [ 2 ]

4 голосов
/ 07 марта 2020

Нет. У вас не может быть объекта типа void. Тем не менее, вам не нужна специализация. Все, что вам нужно, это перегрузка:

int GetValue()
{
    return 25;
}

template <class Increment>
int GetValue(const Increment& inc)
{
    return GetValue() + inc;
}

Другой вариант - по умолчанию использовать параметр шаблона, отличный от void:

template <class Increment = int>
int GetValue(const Increment& inc = {})
{
    return 25 + inc;
}

GetValue(), после чего вызов становится эффективным GetValue(0), что также делает работу.

3 голосов
/ 07 марта 2020

Вот идея, основанная на шаблонах variadi c:

template <typename ...INCREMENT>
int GetValue(const INCREMENT &...inc) {
    // this "if" is not actually needed for this example, but if you want
    // to discriminate between zero/non-zero number of parameters,
    // it can be done this way
    if constexpr (sizeof...(inc) == 0) {
        return 25;
    } else {
        return (25 + ... + inc);
        // or you can use this:
        // const auto &i = (inc, ...);
        // return 25 + i;
    }
}

int main() {
    std::cout<<GetValue(1)<<"\n";
    std::cout<<GetValue()<<"\n";
}

Обратите внимание, что это решение допускает любое количество параметров. Если у вас должен быть ноль или один параметр GetValue, я думаю, что вы можете использовать SFINAE, чтобы разрешить только один параметр.

(например, вы можете использовать std::enable_if_t<sizeof...(INCREMENT)<=1, int> в качестве возвращаемого типа функции)

...