Использование аргументов шаблона void в переполнении стека

Возьмите следующий минимальный пример:

using Type1 = std::function<void(void)>;

template <typename T>
using Type2 = std::function<void(T)>;

Type1 whyDoesThisWork;
Type2<void> andYetThisDoesNot;

Если псевдоним второго типа, я получаю сообщение об ошибке «Аргумент может не иметь типа« void »». (Я тестировал с Xcode 4.5, Clang / c ++ 11 / libc ++, OS X 10.7.)

Я нахожу это любопытным: я бы ожидал Type1 а также Type2<void> вести себя одинаково. Что тут происходит? И есть ли способ переписать псевдоним второго типа, чтобы я Можно записывать Type2<void> и получить std::function<void(void)> вместо ошибки?

редактировать Я, вероятно, должен добавить, что причина, по которой я хочу это, состоит в том, чтобы учесть что-то вроде следующего:

template <typename ... T>
using Continuation = std::function<void(T...)>;

auto someFunc = []() -> void {
printf("I'm returning void!\n");
};

Continuation<decltype(someFunc())> c;

Continuation<decltype(someFunc())> становится Continuation<void> и я получаю ошибку.

18

Решение

Краткий ответ: «шаблоны не являются подстановкой строк». void f(void) имеет значение только постольку, поскольку void f() в C ++ для обратной совместимости с C.

Первый шаг состоит в том, чтобы использовать вариадику, как отмечено в другом месте.

Второй шаг — выяснить, как составить карту void возвращая функции к … ну, может быть что-то вроде std::function<void()>или, может быть, что-то еще. Я говорю, может быть, что-то еще, потому что в отличие от других случаев, вы не можете позвонить std::function<void()> foo; foo( []()->void {} ); — это не настоящее продолжение.

Что-то вроде этого может быть:

template<typename T>
struct Continuation
{
typedef std::function<void(T)> type;
};

template<>
struct Continuation<void>
{
typedef std::function<void()> type;
};

затем используйте это так:

auto someFunc = []()->void {};
Continuation<decltype(someFunc())>::type c;

который дает вам тип, который вы хотите. Вы можете даже добавить заявку на продолжение:

template<typename T>
struct Continuation
{
typedef std::function<void(T)> type;

template<typename func, typename... Args>
static void Apply( type const& cont, func&& f, Args... args)
{
cont( f(args...) );
}
};

template<>
struct Continuation<void>
{
typedef std::function<void()> type;
template<typename func, typename... Args>
static void Apply( type const& cont, func&& f, Args... args)
{
f(args...);
cont();
}
};

который позволяет применять продолжение к выполнению функции единообразно, если входящий тип является пустым или если он не является пустым типом.

Тем не менее, я хотел бы спросить «почему вы хотите это сделать»?

11

Другие решения

У меня нет фактического ответа, только то, что я сказал в комментарии: вы не можете иметь void как тип функции, как в:

int foo(int, char, void, bool, void, void);     // nonsense!

я полагаю, что T(void) допускается только как обозначение совместимости для C (который отличает декларации а также прототипы, очень отличается от C ++, и который должен быть в состоянии сказать «без аргументов»).

Итак, решение должно быть вариативным:

template <typename ...Args> using myType = std::function<void(Args...)>;

Таким образом, вы можете правильно иметь без аргументов:

myType<> f = []() { std::cout << "Boo\n"; }
11

Несколько ответов уже объясняют обоснование. Чтобы добавить к этим ответам, спецификация говорит (C ++ 11 §8.3.5 [dcl.func] / 4):

Список параметров, состоящий из одного безымянного параметра независимого типа void является
эквивалентно пустому списку параметров. За исключением этого особого случая, параметр не должен иметь тип резюме void,

В вашем Type2 Например, T в void(T) это зависимый тип—это зависит от параметра шаблона.

5

Когда объявлена ​​функция, принимающая параметр типа void, как в std::function<void(void)>это действительно глупый способ сказать, что он принимает нулевые параметры. Но способ, которым вы объявили Type2 как std::function с подписью, которая ничего не возвращает (void), но принимает 1 параметр. void — это не тип, который можно использовать в качестве параметра, это просто способ объявить, что параметров нет. Так что он не работает с Type2, потому что для этого требуется фактический тип, который можно использовать в качестве параметра.

3

Void можно интерпретировать как пустой параметр, если вы передадите его функции. Вы не используете пустой указатель в конце концов, так

void func (void)

становится

void func ()
0
По вопросам рекламы [email protected]