SFINAE z nieprawidłowymi parametrami typu function czy array?

Proszę wziąć pod uwagę ten kod:

template<typename T>
char (&f(T[1]))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

Spodziewałam się, że zrobi SFINAE i wybierze drugie przeciążenie, ponieważ Zamiana T na T[1] daje

 void [1]()

Który jest nieprawidłowym typem, oczywiście. Dostosowanie typów parametrów (array - >pointer) odbywa się po zamianie parametrów szablonu na parametry funkcji i sprawdzeniu poprawnych typów wynikowych, takich jak 14.8.2 [temp.odliczenie] opisuje.

Ale zarówno comeau, jak i GCC nie kompilują powyższego. Zarówno z różnymi diagnostyka.

Comeau mówi:

"Chodź.c", linia 2: Błąd: tablica funkcji jest niedozwolona char (&f(T[1]))[1];

GCC mówi (wersja 4.3.3):

Błąd: ISO C++ zabrania tablicy o rozmiarze zerowym c

Oznacza, że GCC nie może zastąpić, ale wybiera pierwsze przeciążenie f, zwracając sizeof z 1, zamiast nie zastępować go z przodu, jak Comeau.

Jaki kompilator ma rację i czy mój kod jest w ogóle poprawny? Proszę zapoznać się z odpowiednią częścią standardową lub zacytować ją w odpowiedzi. Dzięki!


Update : Sam Standard zawiera taki przykład na liście w 14.8.2/2. Nie wiem dlaczego pierwszy to przeoczyłem:

template <class T> int f(T[5]);
int I = f<int>(0);
int j = f<void>(0); // invalid array

Chociaż przykład ma jedynie charakter informacyjny, pokazuje intencję wszystkich tych tajemniczych akapitów i wydaje się, że powyższy kod powinien działać i odrzucić pierwsze przeciążenie.

Author: Johannes Schaub - litb, 2009-05-05

3 answers

Mała notka, choć bardzo rzadka, znalazłem kilka okazji, w których wierzyć, że kompilator Comeau się myli - chociaż te okazje są tak rzadkie, że zawsze warto podwójnie i potrójnie sprawdzam twoje założenia!

Mogę mieć powód do zachowania g++. Nie jestem pewien, czy to podany dokładnie, gdy typy parametrów są dostosowywane:

Rozważ, co następuje:

template<typename T>
struct A
{
  void bar (T[10]);
};

template<typename T>
void A<T>::bar (T*)
{
}

Definicja " bar "jest legalna, ponieważ" T[10] "rozpada się na"T*". Tak. nie widzę nic w standard, który zabrania kompilatorowi wykonanie korekt określonych w pkt 8.3.5 w odniesieniu do deklaracji wzorcowej, poprawia również wydajność, jeśli chodzi o dopasowanie przeciążenia.

Stosując to do twojego przykładu, g++ może traktować to jako:

template<typename T>
char (&f( T* ))[1];

template<typename T>
char (&f(...))[2];

int main() { char c[sizeof(f<void()>(0)) == 2]; }

W powyższym parametrze podstawiony jest prawnym wskaźnikiem do funkcji, a nie tablicy funkcji.

Więc, pytanie dla mnie jest - czy jest coś, co zabrania korekty dla funkcji parametry (8.3.5) dwa razy?

[[3]} osobiście uważam, że to ma sens, aby umożliwić dostosowanie się do dwa razy, bo inaczej komplikuje dopasowanie szablonu funkcji przeciążenia

Podsumowując, myślę, że to poprawne dla g++, aby wybrać pierwsze przeciążenie opierając się na tym, jak traktuje rozkładające się parametry tablicy, a Comeau jest błędne nie mieć błędu dedukcyjnego dla tablicy funkcji.

Oczywiście teraz oznacza to, że (jeśli Comeau został naprawiony) wtedy każdy kompilator wybierze różne przeciążenia i nadal będzie standardy posłuszny! :(

EDIT:

Aby zilustrować mój punkt widzenia, rozważ następujący kod:

template <typename T> void foo ( T * );
template <typename T> void foo ( T * const );
template <typename T> void foo ( T [] );
template <typename T> void foo ( T [10] );
template <typename T> void foo ( T [100] );

void bar () 
{
  foo < void() > ( 0 );
}

Tutaj foo zostało zadeklarowane i ponownie zgłoszone kilka razy. Która deklaracja, a więc jaki typ parametru, powinien stosować reguły wymienione w 14.8.2?

Chodzi mi o to, że standard nic nie mówi o powyższym. Posunąłbym się również do stwierdzenia, że każde sformułowanie w tej sprawie musiałoby zostawić jest to zachowanie" undefined "lub" implementation defined".

 12
Author: Richard Corden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-21 17:44:15

Zaskakujące-to działa w VS2008. Nie sądzę, że to koniecznie dowód na to, że jest to poprawne zachowanie,czy nie...

Visual Studio interpretuje

char (&f(T[1]))[1];

Jako funkcja, która pobiera tablicę o rozmiarze 1 T i zwraca odwołanie do tablicy znaków o rozmiarze 1.

 1
Author: Eclipse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 21:36:53

Postaram się opisać proces dedukcji argumentu szablonu, jak rozumiem to z lektury standardu.

  1. jawne argumenty szablonu są sprawdzane zgodnie z opisem w 14.8.2 / 2.
  2. wynikowa sygnatura funkcji jest dostosowywana zgodnie z 8.3.5 (tzn. wykonywana jest zanik tablicy do wskaźnika).
  3. domyślne argumenty szablonu są wyprowadzane zgodnie z pkt 14.8.2.1 (odbywa się to na częściowo podstawionym podpisie z etapu 2).

Odliczenie za pierwsze przeciążenie nie powiedzie się w kroku 1, dlatego rozdzielczość przeciążenia zwraca drugie przeciążenie. Nie wierzę, że program jest źle uformowany.

 1
Author: avakar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 22:02:10