C/С++: функция вызова без аргументов с функцией, которая ничего не возвращает

Почему нельзя вызвать функцию, которая не принимает аргументов с вызовом функции как аргумент, который не возвращает никакого значения (что ИМХО эквивалентно вызову функции, которая не принимает аргументов без аргументов).

Например:

void foo(void) {...}
void bar(void) {...}

foo(bar())

Не поймите меня неправильно, я знаю, что void не является значением и что его нельзя рассматривать как один.

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

Ответ 1

Я не уверен, что любая из причин, о которых я слышал, хорошие.

См. в С++, вы можете вернуть результат функции void:

void foo() {
    // ...
}

void bar() {
    // ...
    return foo();
}

Да, это точно так же, как:

foo();
return;

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

Итак, если подобная система применяется так, что return void представляет собой нулевой вызов в сценарии компоновки функций, это может также сделать состав функций более общим.

Ответ 2

Поскольку, согласно пункту 3.9.1/9 стандарта,

следует использовать выражение типа void только как выражение (6.2), как операнд выражения для запятой (5.18), как второй или третий операнд of?: (5.16), так как операнд typeid, или как выражение в return (6.6.3) для с возвратом типа void.

C/С++ просто не предназначен для того, чтобы быть общим. Вы получаете return returns_void(); для оптимизации хвостового вызова, это функционально-иш, правильно?: ВС

Изменить: Вышеприведенное правило все равно позволит вам вызвать takes_void(3) с 3, преобразованным в void. Это запрещено в 8.3.5/2:

Если предложение параметра-объявления пусто, функция не принимает аргументы. Список параметров (void) эквивалентно пустому параметру список. За исключением этого специального случая, void не должен быть типом параметра (хотя типы, полученные из void, такие как void *, can).

Ответ 3

Если список параметров (void) обрабатывался равномерно со всеми другими списками параметров в C/С++, семантическое значение, если объявление такого параметра было бы "единственным параметром типа void". Если это так, вполне возможно, что в целях единообразия язык позволил бы "цеплять" вызовы на такие функции, как показано в вашем примере. (По крайней мере, С++, вероятно, будет, поскольку он допускает такую ​​однородность в операторах return).

Однако в языке С++, а также в C список параметров, который имеет форму (void), не обрабатывается равномерно с другими формами списков параметров. Вместо этого это имеет особое значение. Это означает, что функция вообще не имеет параметров. (Эквивалентно пустой () в С++).

Другими словами, функция, объявленная с помощью списка параметров (void), принимает нулевые параметры. Вы его поставляете. Это то, что делает его незаконным. Учитывая особый смысл списка параметров (void) в C/С++, позволяя

foo(bar());

не будет сильно отличаться от разрешения

foo(bar(), bar());
foo(bar(), bar(), bar());

. Качественно, 2 и 3 отличаются от 0, как 1.

Ответ 4

Не вводите в заблуждение нотацию. Скорее раздражающе, C использует прототип f(void) для обозначения "f не ожидает никаких параметров", а не "f ожидает единственный параметр типа void". Обозначение f() содержалось в значении "количество параметров, ожидаемых f, неизвестно, поэтому вы можете называть его любым количеством параметров, которые вам нравятся, и удачи вам". До ANSI Standard C (aka C89) прототипа функции не было, и вам понадобился инструмент, например lint, чтобы защитить вас от даже самых обычных ошибок ошибок с параметрами, таких как передача неправильного количества параметров или передавая параметр с дико несовместимым типом.

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

Ответ 5

он делает какой-то смысл (bar ничего не производит, foo ничего не потребляет, поэтому foo(bar()) должно быть разрешено). OTOH, было бы просто путать читателя. если вы хотите быть l33t, всегда есть ,, && и || для эмуляции точек с запятой.

Ответ 6

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

Ответ 7

Предположите, что это работает. Можете ли вы представить себе один гипотетический случай, когда

bar();
foo();

который делает то же самое, не намного читабельнее и разумнее?

Под ред. Да, да.:)

Ответ 8

В данный момент у меня есть что-то вроде этого в моем коде: #define EVAL (f) f (++ evalcounter) Не спрашивайте меня, почему я его использую, я просто должен это сделать. Обычно f не принимает никаких значений. Я просто добавил это (глобальное) целое число, чтобы считать что-то. Было бы намного лучше, если бы у меня было что-то вроде #define EVAL (f) f (фиктивный (++ evalcounter))?

Пробовали ли вы оператор запятой:

#define EVAL(f)   (++evalcounter, f())

Ответ 9

Я добавлю одно дополнительное объявление: void baz(int);

Теперь очевидно, что если аргумент с типом void не равен аргументам, то два аргумента, один из которых имеет тип void, будет равен одному аргументу (как 0 = 1 * x <= > 1 = 1+ 1 * х)

Итак, очевидно, это законно: baz(1, bar());. Но также (поскольку void "ничего" ) baz(bar(),1);.

И мы можем продолжить в этом смысле: baz(bar(), 1, bar());. В конце концов, "пустота - это ничто".

Либо вы запрещаете его прямо, либо произвольно устанавливаете, либо вы допускаете смешные конструкции. Я согласен с выбором для первой резолюции