函数类型参数的模板参数推导


10

考虑以下程序。

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

该程序编译成功,其输出为

g( 42 );

现在,将非模板函数重命名gf

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

现在该程序不是由gcc HEAD 10.0.0 20200和clang HEAD 10.0.0编译的,而是由Visual C ++ 2019成功编译的。

例如,编译器gcc发出以下消息集。

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

因此出现一个问题:应否编译代码,以及gcc和clang不编译代码的原因是什么?



注意:在第一个示例中,将g(而不是&g)传递给函数模板会导致类型衰减(函数左值引用会衰减到指向函数的指针:void(&)(T)=> void(*)(T))。之所以发生这种隐式转换,是因为没有其他f具有更好匹配的重载。在第二个示例中,f您实际上要调用一个歧义,因为...它也不知道哪个f是参数。
Xeverous

Answers:


7

在我看来,gcc和clang是正确的。这不应该编译。在T此处提供的参数是包含函数模板[temp.deduct.type] /5.5的重载集时,您要从中推断出的函数参数将变为未推断的上下文:

非推论上下文是:

  • […]
  • 由于相关联的函数参数是一个函数或一组重载函数([over.over]),因此无法进行参数推导的函数参数,并且以下一项或多项适用:

    • […]
    • 作为参数提供的一组函数包含一个或多个函数模板。
  • […]

因此,T由于没有转换,因此无法推断出另一个过载是不可行的;gcc到底在说什么…


0

这是两个重载函数,与模板函数相比,应该选择非模板函数,因此选择了f(int x),因此不可能将函数作为参数传递给必须传递int的函数。和下面的应该工作。谢谢

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

  int main(){

     f( f );
  }

仅当在过载解析过程中出现平局时,才首选非模板功能。问题的代码还没有到此为止:从来没有void f<int>(void(int))生成过专门化以便在任一级别上进行重载解析。
戴维斯·鲱鱼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.