2015-04-14 13 views
27

Byłem zaskoczony, gdy dowiedziałem się, że GCC umożliwia funkcjom zwracanie tablic, gdy używany jest zwracający typ powrotu zamiast zwykłego. Jak zapewne wiesz, tablic nie można kopiować, więc jest to dość ograniczone, ale pozwól, że pokażę ci kilka fajnych example.GCC pozwala na zwrócenie tablic z funkcji - błędu lub funkcji?

#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; 
} 

Czy jest to błąd kompilatora lub jakąś nową funkcję?

Co ciekawe "typid" zwraca "FA5_ivE", który jest demangled jako "int (()) [5]", a to oznacza dokładnie to, co myślisz funkcja zwracająca tablicę 5 int.

EDIT: Próbowałem ograniczająca zwracana tablica do odniesienia rvalue ale bez powodzenia (używany przez większość możliwych formach):

auto &&refArrayTemp{ func() }; 

Wydaje się, że rozszerzenie jest raczej bezużyteczne.

+0

Chyba th w tablicy jest 'static const int []' one ... Jeśli tak jest, kompilator zachowuje się poprawnie. –

+1

@BasileStarynkevitch nie tak; Mogę napisać 'func' pobierający parametry' int' i są one umieszczane w zwróconej tablicy. – ecatmur

Odpowiedz

13

To był bug in gcc (stały as of 2017-07-03), spowodowane niespójnym traktowaniem typów powrotu-powrotu.

Pierwsza uwaga różnica w komunikacie o błędzie między dwoma próbami zadeklarować funkcję powrocie funkcję:

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

Pierwszy błąd pochodzi od decl.c, manipulowania declarators, podczas gdy druga jest o wiele głębiej w wewnętrzne, od tree.c, próbując zbudować typ funkcji przygotowawczej do generowania kodu.

doczepiany zwrotne typy są obsługiwane w decl.c 30 lines below Powyższy błąd - zbyt późno, aby złapać go z powyższym kodem błędu i nie jest obsługiwane oddzielnie.

W przypadku tablic, podobnie użycie typu powrotu z powrotem pozwala pominąć sprawdzanie w decl.c, różnica polega na tym, że tablica zwracająca funkcje jest rzeczywiście poprawna pod względem wewnętrznej reprezentacji gcc.

Należy pamiętać, że nie można z nim wiele zrobić; gcc nie pozwala na przypisanie, odniesienia wiążą, rozpad lub przekazać wynik func() do innej funkcji:

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 

Rzeczywiście, nawet Twój kod zostanie odrzucony na -Wpedantic:

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

Wreszcie, poprzez wykorzystanie podobnego błędu (kwalifikacyjne są usuwane z skalarów przed zabiegiem spływu zwrotny typów) możemy utworzyć funkcję z rodzaju int const volatile():

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

Nie naprawiaj tego. Raczej zezwól na operacje tablicowe. Byłoby bardzo miło, gdybyś to zrobił. Podobnie jak kopiowanie tablicowe według wartości i odwoływanie się do referencji "rvalue". Żadna kompatybilność nie zostanie utracona i nie sądzę, że będzie to trudne, ale ułatwi nam życie. – AnArrayOfFunctions

+6

@FISOCPP Już możesz. 'std :: array' jest o wiele lepszy niż wbudowana tablica typu C. – edmz

+0

Ale dlaczego nie pozwolić na oba? Wbudowane macierze wyglądają o wiele bardziej cool. – AnArrayOfFunctions

8

Najnowsza wersja [dcl.array]/P10:

funkcje nie mają typu zwrotnego macierzowych lub funkcji, ale mogą one mieć typu zwrotnego typu wskaźnik lub odniesienie do takiego rzeczy. Nie będzie tablic funkcji, chociaż mogą być tablice wskaźników do funkcji.

Może to być niestandardowe rozszerzenie GCC. It doesn't compile in the trunk version of clang. Jednak może to być również błąd, ponieważ ma niespójne zachowanie z non-trailing return type.

+0

Co? To znaczy, wiedzieliśmy, że to nie jest legalne i może być błędem lub jakimś rozszerzeniem. – edmz

+0

@black Co masz na myśli? – 0x499602D2

Powiązane problemy