Domanda

Ti preghiamo di considerare questo codice:

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

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

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

Mi aspettavo che facesse SFINAE e che eliminasse il secondo sovraccarico, poiché la sostituzione di T in T [1] produce

 void [1]()

Che è un tipo non valido, ovviamente. La regolazione dei tipi di parametri (array- > pointer) viene eseguita dopo aver sostituito i parametri del modello in parametri di funzione e verificato la presenza di tipi risultanti validi come descritto da 14.8.2 [temp.deduct].

Ma sia comeau che GCC non riescono a compilare quanto sopra. Entrambi con diagnostica diversa.

Comeau dice:

  

" ComeauTest.c " ;, riga 2: errore: array di funzioni non consentito char (& amp; f (T [1])) [1];

GCC dice (versione 4.3.3 ):

  

errore: ISO C ++ proibisce l'array di dimensioni zero c

Significato, GCC non riesce a sostituire, ma sceglie il primo sovraccarico di f , restituendo una sizeof di 1, invece di non riuscire a sostituirlo in anticipo come Comeau.

Qual è il compilatore giusto e il mio codice è valido? Si prega di fare riferimento o citare la sezione standard corretta nella risposta. Grazie!


Aggiorna : lo standard stesso contiene un esempio di questo tipo nell'elenco 14.8.2 / 2 . Non so perché l'ho trascurato per primo:

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

Mentre l'esempio è solo informativo, mostra l'intenzione di tutti quei misteriosi paragrafi e sembra mostrare che il codice sopra dovrebbe funzionare e rifiutare il primo sovraccarico.

È stato utile?

Soluzione

Una piccola nota, anche se molto rara, ho trovato alcune occasioni in cui credo che il compilatore Comeau abbia sbagliato, anche se questi le occasioni sono così rare che vale sempre la doppia e la tripla controllando i tuoi presupposti!

Potrei avere una ragione per il comportamento di g ++. Non sono sicuro che sia specificato esattamente quando vengono adattati i tipi di parametro:

Considera quanto segue:

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

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

La definizione di 'bar' è legale, in quanto "T [10]" decade in "T *". lo voglio non vedere nulla nello standard che proibisca al compilatore di eseguire le rettifiche di 8.3.5 rispetto alla dichiarazione del modello, e migliora anche le prestazioni in termini di sovraccarico della corrispondenza.

Applicando questo al tuo esempio, g ++ potrebbe trattarlo come:

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

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

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

In quanto sopra, il parametro sostituito è un puntatore legale a funzione, piuttosto che una serie di funzioni.

Quindi, la domanda per me è - è se c'è qualcosa che proibisce le regolazioni per i parametri della funzione (8.3.5) due volte?

Personalmente, penso che abbia senso consentire gli aggiustamenti due volte poiché altrimenti complica la corrispondenza del modello di funzione sovraccarichi

In conclusione, penso che sia valido per g ++ per selezionare il primo sovraccarico in base al modo in cui tratta i parametri di array in decomposizione e Comeau è errato non avere un errore di detrazione per l'array di funzioni.

Ovviamente questo ora significa che (se Comeau è stato corretto) allora ogni compilatore sceglierebbe un sovraccarico diverso e sarebbe comunque standard conforme! : (

Modifica

Solo per illustrare il mio punto, considera il seguente codice:

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

Qui, foo è stato dichiarato e ridecorato più volte. Quale dichiarazione, e quindi quale tipo di parametro, il compilatore dovrebbe applicare le regole elencate in 14.8.2?

Il mio punto è che lo standard non dice nulla di quanto sopra. Vorrei anche dire che qualsiasi formulazione su questo dovrebbe lasciarlo come "non definito". o " implementazione definita " comportamento.

Altri suggerimenti

Sorprendentemente, questo funziona in VS2008. Non penso che sia necessariamente una prova del fatto che si tratti di un comportamento corretto o meno ...

Visual Studio sta interpretando

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

come funzione che accetta un array di dimensioni 1 di T e restituisce un riferimento a un array di caratteri di dimensioni 1.

Proverò a descrivere il processo di deduzione dell'argomento template mentre lo capisco leggendo lo standard.

  1. Gli argomenti espliciti del modello sono controllati come descritto in 14.8.2 / 2.
  2. La firma della funzione risultante viene regolata come da 8.3.5 (ovvero viene eseguito il decadimento da array a puntatore).
  3. Gli argomenti impliciti del modello sono dedotti come da 14.8.2.1 (questo viene eseguito su una firma parzialmente sostituita dal passaggio 2).

La detrazione per il primo sovraccarico fallisce nel passaggio 1, la risoluzione del sovraccarico quindi restituisce il secondo sovraccarico. Non credo che il programma sia mal formato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top