Подтвердить что ты не робот

GCC позволяет возвращать массивы из функции - ошибка или функция?

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

#include <iostream>
#include <typeinfo>

using namespace std;

auto func() -> int [5]
{
    return {4, 56, 78, 4, 0};
}

int main()
{
    cout << func()[2] << endl;
    cout << typeid(func).name() << endl;
}

Является ли это ошибкой компилятора или какой-то новой функцией?

Интересно, что "typeid" возвращает "FA5_ivE", который разворачивается как "int (()) [5]", и это означает, что вы считаете, что функция возвращает массив из 5 int.

EDIT: я попытался ограничить возвращаемый массив ссылкой на rvalue, но без каких-либо успехов (использовал большинство возможных форм):

auto &&refArrayTemp{ func() };

Похоже, что эти расширения довольно бесполезны.

4b9b3361

Ответ 1

Это была ошибка в gcc (исправлено с 2017 года -07-03), вызванные непоследовательным отношением типов возвращаемых возвратов.

Сначала обратите внимание на разницу в сообщении об ошибке между двумя попытками объявить функцию, возвращающую функцию:

using Fv = void();
Fv f1();             // error: 'f1' declared as function returning a function
auto f2() -> Fv;     // error: function return type cannot be function

Первая ошибка исходит из decl.c, обрабатывая деклараторы, а вторая намного глубже во внутренностях, от tree.c, пытаясь построить тип функции, подготовительный к генерации кода.

Обратно-возвращаемые типы обрабатываются в decl.c 30 строк ниже вышеуказанная ошибка - слишком поздно, чтобы поймать ее с приведенной выше ошибкой кода, и он не обрабатывается отдельно.

С помощью массивов аналогичным образом с использованием типа trailing-return мы можем пропустить проверки в decl.c, разница состоит в том, что функция-возвращающий-массив действительно действителен в терминах внутреннего представления gcc.

Обратите внимание, что вы не можете много сделать с ним; gcc не позволяет назначать, ссылаться на привязку, распадаться или передавать результат func() другой функции:

auto a1 = func();
// error: invalid use of non-lvalue array

auto& a2 = func();
// error: invalid initialization of non-const reference of type 'int (&)[5]' from an rvalue of type 'int [5]'

auto&& a3 = func();
// error: lvalue required as unary '&' operand

Действительно, даже ваш код отклоняется в -Wpedantic:

warning: ISO C++ forbids subscripting non-lvalue array

Наконец, используя подобную ошибку (отделители отделяются от скаляров перед обработкой возвращающих-возвращаемых типов), мы можем создать функцию с типом int const volatile():

int const volatile g1();          // warning: type qualifiers ignored on function return type
auto g2() -> int const volatile;  // OK!!

Ответ 2

Последний черновик, [dcl.array]/p10:

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

Это может быть нестандартное расширение GCC. Он не компилируется в trunk-версии clang. Однако это также может быть ошибкой, поскольку она имеет непоследовательное поведение с не возвращающий назад тип возврата.