c++ - 函数类型参数的模板参数推导

标签 c++ templates language-lawyer c++17 template-argument-deduction

考虑以下程序。

#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没有编译的原因是什么?

最佳答案

在我看来 gcc 和 clang 是正确的。这不应该编译。您希望从中获取的函数参数 T当提供的参数是一个包含函数模板的重载集时,要推导的上下文就变成了一个非推导的上下文 [temp.deduct.type]/5.5 :

The non-deduced contexts are:

  • […]
  • A function parameter for which argument deduction cannot be done because the associated function argument is a function, or a set of overloaded functions ([over.over]), and one or more of the following apply:

    • […]
    • the set of functions supplied as an argument contains one or more function templates.
  • […]


因此,T无法推导出,并且由于没有转换,其他重载不可行;正是 gcc 所说的......

关于c++ - 函数类型参数的模板参数推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59787879/

相关文章:

c++ - C++ 整数除法如何用于限制和负值?

c++ - 使用 SFINAE 进行结构定义

c++ - boost 软件集成

c++ - std::string 是否保证不会自发归还内存?

c - 有符号固定宽度整数上是否定义了按位运算并可移植?

c++ - 每当我放置一个字符串而不是一个nlohmann::json对象时,是否有一种方法可使编译器抛出错误?

c++ - 如何在Qt5中的QToolButton上设置GIF图像

c++ - std::map::iterators post increment 的奇怪行为

c++ - 模板化类构造函数的模板实例化

c++ - 在什么意义上 const 只允许对可变成员变量进行原子更改?