Возврат из функции Void в С++

Рассмотрим следующий фрагмент:

void Foo()
{
  // ...
}

void Bar()
{
  return Foo();
}

Что является законной причиной использования вышеуказанного в С++ в отличие от более распространенного подхода:

void Foo()
{
  // ...
}

void Bar()
{
  Foo();

  // no more expressions -- i.e., implicit return here
}

Ответ 1

Вероятно, вам не нужно использовать в вашем примере, но есть некоторые ситуации, когда с шаблоном кода трудно справиться с void, и я ожидаю, что это правило иногда помогает. Очень надуманный пример:

#include <iostream>

template <typename T>
T retval() {
    return T();
}

template <>
void retval() {
    return;
}

template <>
int retval() {
    return 23;
}

template <typename T>
T do_something() {
    std::cout << "doing something\n";
}

template <typename T>
T do_something_and_return() {
    do_something<T>();
    return retval<T>();
}

int main() {
    std::cout << do_something_and_return<int>() << "\n";
    std::cout << do_something_and_return<void*>() << "\n";
    do_something_and_return<void>();
}

Обратите внимание, что только main должен справиться с тем, что в случае void нет возврата к retval. Промежуточная функция do_something_and_return является общей.

Конечно, это доводит вас до сих пор - если do_something_and_return захотелось в нормальном случае сохранить retval в переменной и сделать что-то с ней перед возвратом, тогда вы все равно будете в беде - d должны специализироваться (или перегружать) do_something_and_return для void.

Ответ 2

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

Ответ 3

Вы использовали бы его в общем коде, где возвращаемое значение Foo() неизвестно или может быть изменено. Рассмотрим:

template<typename Foo, typename T> T Bar(Foo f) {
    return f();
}

В этом случае Bar действителен для void, но также действителен, если тип возвращаемого значения изменится. Однако, если это просто называется f, тогда этот код сломается, если T не является void. Используя возврат f(); синтаксис гарантирует сохранение возвращаемого значения Foo(), если он существует, и допускает void().

Кроме того, явно возвращается хорошая привычка.

Ответ 4

Шаблоны:

template <typename T, typename R>
R some_kind_of_wrapper(R (*func)(T), T t)
{
   /* Do something interesting to t */
   return func(t);
}

int func1(int i) { /* ... */ return i; }

void func2(const std::string& str) { /* ... */ }

int main()
{
   int i = some_kind_of_wrapper(&func1, 42);

   some_kind_of_wrapper(&func2, "Hello, World!");

   return 0;
}

Не имея возможности вернуть void, return func(t) в шаблоне не будет работать, когда его попросят обернуть func2.

Ответ 5

Единственная причина, по которой я могу думать, - это иметь длинный список операторов return Foo(); в коммутаторе и хотел бы сделать его более компактным.

Ответ 6

Причиной является возвращение памяти, так как math.h всегда возвращается. У math.h нет пустоты и нет пустых аргументов. Существует много практических ситуаций, в которых вам нужна память.

Ответ 7

Может быть случай, когда Foo() изначально возвратил значение, но позже был изменен на void, и человек, который его обновил, просто не думал очень четко.