Pengurangan argumen template untuk argumen tipe fungsi


10

Pertimbangkan program berikut.

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

Program berhasil dikompilasi dan hasilnya adalah

g( 42 );

Sekarang mari kita ganti nama fungsi non-templat gmenjadi 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 );
}

Sekarang program tidak dikompilasi oleh gcc HEAD 10.0.0 20200 dan clang HEAD 10.0.0 tetapi berhasil dikompilasi oleh Visual C ++ 2019 ..

Sebagai contoh, compiler gcc mengeluarkan set pesan berikut.

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 )
      |         ~~~~^

Maka muncul pertanyaan: haruskah kode dikompilasi dan apa alasannya kode tersebut tidak dikompilasi oleh gcc dan dentang?



Catatan: pada contoh pertama, meneruskan g(alih-alih &g) ke templat fungsi menyebabkan peluruhan tipe (referensi nilai fungsi meluruh ke penunjuk ke fungsi: void(&)(T)=> void(*)(T)). Konversi tersirat ini terjadi karena tidak ada fkelebihan lainnya dengan kecocokan yang lebih baik. Pada contoh kedua, ada ambiguitas yang fingin Anda panggil karena ... tidak tahu yang mana fargumennya.
— Xeverous

Jawaban:


7

Sepertinya saya bahwa gcc dan dentang benar. Ini seharusnya tidak dikompilasi. Parameter fungsi dari mana Anda ingin Tdideduksi menjadi konteks non-deduksi di sini saat argumen yang diberikan adalah kumpulan kelebihan yang berisi templat fungsi [temp.deduct.type] /5.5 :

Konteks yang tidak dideduksi adalah:

  • [...]
  • Parameter fungsi yang pengurangan argumennya tidak dapat dilakukan karena argumen fungsi yang terkait adalah fungsi, atau sekumpulan fungsi kelebihan beban ([over.over]), dan satu atau lebih dari yang berikut ini berlaku:

    • [...]
    • set fungsi yang disediakan sebagai argumen berisi satu atau beberapa templat fungsi.
  • [...]

Dengan demikian, Ttidak dapat disimpulkan dan kelebihan lainnya tidak layak karena tidak ada konversi; persis apa yang dikatakan gcc ...


0

Ini adalah dua fungsi kelebihan beban dan fungsi non-templat harus dipilih dibandingkan dengan fungsi templated, jadi f (int x) dipilih maka melewati fungsi sebagai argumen dalam fungsi yang int harus dilewati adalah mustahil. dan di bawah ini akan berfungsi. Terima kasih

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

  int main(){

     f( f );
  }

Fungsi non-templat lebih disukai hanya jika ada ikatan selama resolusi kelebihan beban. Kode pertanyaan tidak sampai ke titik itu: tidak pernah ada spesialisasi yang void f<int>(void(int))dihasilkan untuk melakukan resolusi kelebihan pada kedua level.
— Davis Herring
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.