C++函数类型模板参数推导规则

标签 c++ templates function-pointers

使用以下代码构建时

clang -Wall main.cpp -o main.o

生成以下诊断信息(在代码之后):
template <typename F>
void fun(const F& f)
{

}

template <typename F>
void fun(F f)
{

}

double Test(double d) { return d; }

int main(int argc, const char * argv[])
{
    fun(Test);

    return 0;
}

诊断:
main.cpp:17:5: error: call to 'fun' is ambiguous
    fun(Test);
    ^~~
main.cpp:2:6: note: candidate function [with F = double (double)]
void fun(const F& f)
     ^
main.cpp:8:6: note: candidate function [with F = double (*)(double)]
void fun(F f)
     ^
1 error generated.

有趣的部分不是关于歧义错误本身(这不是这里的主要问题)。有趣的部分是模板参数F第一个 fun解析为 double (double) 的纯函数类型, 而模板参数 F第二个 fun解析为更值得期待的double (*)(double)函数指针类型,当仅使用函数名称调用 fun 时。

但是,当我们更改 fun(Test) 的调用时成为 fun(&Test)显式获取函数的地址(或显式函数指针),然后都是 fun解析模板参数F成为 double (*)(double) !

这种行为似乎是所有 Clang 和 GCC(以及 Visual Studio 2013)的共同行为。

那么问题来了:我的示例代码中给出的形式中的模板函数的函数类型模板参数推导规则是什么?

PS:如果我们添加另一个 fun 的实例取F* f ,那么似乎重载规则只是决定选择这个版本,根本没有报告任何歧义(尽管,正如我已经说过的,歧义不是之前最大的问题,但在最后一种情况下,我不知道为什么第三个版本是这里最好的匹配?)
template <typename F>
void fun(F* f)
{
}

最佳答案

可能其他人可以比我更好地解释这一点,但这就是我的理解(没有引用标准,抱歉)。

不能复制函数类型的变量,因此在 template <typename F> void fun(F f) 中, F 不能具有函数类型。

但是,函数类型的变量可以转换为指向函数类型的指针(这称为“衰减”,就像数组到指针的转换一样),因此当匹配函数类型与 template <typename F> void fun(F f) 时, F 必须是指向一个函数。

在处理对函数类型的引用时,不会发生函数到指针的衰减(我在标准中找不到,但应与引用到数组的规则一起描述),因此在匹配模板 <typename F> void fun(const F& f) 时, F 是一个函数类型(并且参数的类型是对函数的引用)。

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

相关文章:

c++ - 将值放入二维数组

json - 带有 to_nice_json : Unexpected templating type error occurred. ..not JSON 可序列化的 Ansible Vault 内联变量

c++ - 非依赖名称的重载解析何时发生,在定义上下文或实例化点?

c++ - 指向构造函数重载的指针?

使用依赖于类的类型和函数在类的所有实例中具有相同值的 C++ 变量

c - 结构和函数的段错误

c++ - 如何在 Linux (Ubuntu) 中使用 FreeImage 库静态编译 C/C++ 应用程序?

c++ - const int &x = 4 和 const int x = 4 之间的区别

c++ - 在另一个类的构造函数中创建 n 个对象的最佳方法?

c++ - C++ 中与模板相关的语法元素的名称分类