Deduzione dell'argomento modello per un argomento di un tipo di funzione


10

Considera il seguente programma.

#include <iostream>

template <typename T>
void f( void ( *fn )( T ) )
{
    fn( 42 );
}

void g( int x )
{
    std::cout << "g( " << x << " );\n";
}

int main()
{
    f( g );
}

Il programma viene compilato correttamente e il suo output è

g( 42 );

Ora rinominiamo la funzione non modello gin f.

#include <iostream>

template <typename T>
void f( void ( *fn )( T ) )
{
    fn( 42 );
}

void f( int x )
{
    std::cout << "f( " << x << " );\n"; 
}

int main()
{
    f( f );
}

Ora il programma non è compilato da gcc HEAD 10.0.0 20200 e clang HEAD 10.0.0 ma compilato con successo da Visual C ++ 2019 ..

Ad esempio il compilatore gcc emette il seguente set di messaggi.

prog.cc: In function 'int main()':
prog.cc:22:10: error: no matching function for call to 'f(<unresolved overloaded function type>)'
   22 |     f( f );
      |          ^
prog.cc:4:6: note: candidate: 'template<class T> void f(void (*)(T))'
    4 | void f( void ( *fn )( T ) )
      |      ^
prog.cc:4:6: note:   template argument deduction/substitution failed:
prog.cc:22:10: note:   couldn't deduce template parameter 'T'
   22 |     f( f );
      |          ^
prog.cc:14:6: note: candidate: 'void f(int)'
   14 | void f( int x )
      |      ^
prog.cc:14:13: note:   no known conversion for argument 1 from '<unresolved overloaded function type>' to 'int'
   14 | void f( int x )
      |         ~~~~^

Quindi sorge una domanda: il codice dovrebbe essere compilato e qual è la ragione per cui il codice non è compilato da gcc e clang?



Nota: nel primo esempio, il passaggio g(anziché &g) al modello di funzione provoca un decadimento del tipo (un riferimento al valore di una funzione decade in un puntatore a una funzione: void(&)(T)=> void(*)(T)). Questa conversione implicita avviene perché non c'è altro fsovraccarico con una corrispondenza migliore. Nel secondo esempio, c'è un'ambiguità che fin realtà vuoi chiamare perché ... non sa nemmeno quale fsia l'argomento.
Xeverous

Risposte:


7

Mi sembra che gcc e clang siano corretti. Questo non dovrebbe compilare. Il parametro della funzione da cui si desidera Tdedurre diventa qui un contesto non dedotto nel momento in cui l'argomento fornito è un set di sovraccarico che contiene un modello di funzione [temp.deduct.type] /5.5 :

I contesti non dedotti sono:

  • [...]
  • Un parametro di funzione per il quale non è possibile eseguire la deduzione dell'argomento perché l'argomento della funzione associata è una funzione o un insieme di funzioni sovraccaricate ([over.over]) e si applicano una o più delle seguenti condizioni:

    • [...]
    • l'insieme di funzioni fornito come argomento contiene uno o più modelli di funzione.
  • [...]

Pertanto, Tnon può essere dedotto e l'altro sovraccarico non è praticabile a causa della mancata conversione; esattamente cosa dice gcc ...


0

Queste sono due funzioni sovraccaricate e la funzione non template deve essere selezionata rispetto alla funzione template, quindi è stato selezionato f (int x) quindi passare una funzione come argomento nella funzione che int deve essere passato è impossibile. e il seguito dovrebbe funzionare. Grazie

void f( void ( *fn )( int ) ){
  fn( 42 );
}
void f( int x ){
    std::cout << "f( " << x << " );\n";
  }

  int main(){

     f( f );
  }

Le funzioni non modello sono preferite solo quando c'è altrimenti un pareggio durante la risoluzione del sovraccarico. Il codice della domanda non arriva a quel punto: non viene mai void f<int>(void(int))generata una specializzazione in modo da sovraccaricare la risoluzione a nessuno dei due livelli.
Davis Herring il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.