Bir işlev türünün bağımsız değişkeni için şablon bağımsız değişkeninin kesilmesi


10

Aşağıdaki programı düşünün.

#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 başarıyla derlenir ve çıktısı

g( 42 );

Şimdi şablon olmayan işlev adlandırmak izin giçin 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 );
}

Şimdi program gcc HEAD 10.0.0 20200 ve clang HEAD 10.0.0 tarafından derlenmemiştir ancak Visual C ++ 2019 tarafından başarıyla derlenmiştir.

Örneğin derleyici gcc aşağıdaki ileti kümesini yayınlar.

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

Yani bir soru ortaya çıkıyor: kod derlenmeli ve kodun gcc ve clang tarafından derlenmemesinin nedeni nedir?



Not: ilk örnekte, işlev şablonuna g(yerine &g) geçilmesi bir tür bozulmaya neden olur (işlev lvalue başvurusu, bir işleve giden bir işaretçiye bozulur: void(&)(T)=> void(*)(T)). Bu örtük dönüştürme, fdaha iyi eşleşmeye sahip başka bir aşırı yüklenme olmadığı için olur . İkinci örnekte, faslında aramak istediğiniz bir belirsizlik var çünkü ... fargümanın hangisi olduğunu bilmiyor .
Xeverous

Yanıtlar:


7

Bana öyle görünüyor ki gcc ve clang doğru. Bu derlenmemelidir. İstediğiniz işlev parametresiTÇıkarılmak burada sağlanan bağımsız değişken bir işlev şablonu [temp.deduct.type] /5.5 içeren bir aşırı yük kümesi olduğunda, çıkarılmamış bir bağlam haline gelir :

Çıkarılmayan bağlamlar şunlardır:

  • [...]
  • İlişkili işlev bağımsız değişkeni bir işlev veya aşırı yüklenmiş işlevler kümesi ([over.over]) olduğundan ve aşağıdakilerden biri veya daha fazlası geçerli olduğu için bağımsız değişken kesinti yapılamayan bir işlev parametresi:

    • [...]
    • bağımsız değişken olarak sağlanan işlevler kümesi bir veya daha fazla işlev şablonu içerir.
  • [...]

Bu nedenle, Thiçbir dönüşüm olmadığı için çıkartılamaz ve diğer aşırı yüklenme mümkün değildir; gcc tam olarak ne diyor…


0

Bunlar iki aşırı yüklenmiş işlevdir ve şablon olmayan işlev şablonlanmış işleve göre seçilmelidir, bu nedenle f (int x) seçilmiştir, bu nedenle işlevin int içinde geçirilmesi gereken bir argüman olarak geçirilmesi imkansızdır. ve aşağıda çalışmalıdır. Teşekkürler

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

  int main(){

     f( f );
  }

Şablon olmayan fonksiyonlar, yalnızca aşırı yük çözünürlüğü sırasında başka bir bağ olduğunda tercih edilir. Sorunun kodu bu noktaya gelmiyor: Her iki düzeyde void f<int>(void(int))de aşırı yük çözünürlüğü yapmak için asla bir uzmanlık oluşturulmuyor .
Davis Herring
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.