当前位置: 首页 > 知识库问答 >
问题:

当模板函数按一定顺序放置时,代码不编译

单修德
2023-03-14

下面的程序编译成功。

template<typename T>
T sum(T x) {
    return x;
}

template<typename T, typename... Args>
T sum(T x, Args... args) {
    return x + sum(args...);
    
}

int main() {
    sum(1, 2, 3, 4, 5);

}

然而,当我改变模板函数的编写顺序时,它不再编译:

template<typename T, typename... Args>
T sum(T x, Args... args) {
    return x + sum(args...);

}

template<typename T>
T sum(T x) {
    return x;
}

int main() {
    sum(1, 2, 3, 4, 5);

}

为什么会这样?这两个函数不是在main()中调用之前就已经定义好了吗?为什么它们的书写顺序很重要?

共有1个答案

顾昌翰
2023-03-14

你的问题的核心是下面这个问题:当一个函数名,比如< code>sum,出现在一个函数模板中时,它指的是什么函数?

你写道:

这两个函数不是在main()中调用之前就已经定义好了吗?为什么它们的书写顺序很重要?

您似乎有以下期望:当实例化函数模板,并且其中出现函数名称(如 sum)时,编译器会查找到目前为止已声明的所有 sum 重载。因此,根据您的理论,由于 sum 函数模板在 main 中被调用之前不会实例化,因此在这一点上,两个 sum 重载都是可见的,因此对 sum 的递归调用应该同时考虑两个重载,并最终选择一元的重载来终止递归。

然而,如你所见,事实并非如此。如果先声明变量< code>sum,它最终会用一个参数递归调用自身(忽略后面声明的一元< code>sum重载),然后尝试调用< code>sum()(无参数),导致编译错误。

因此,在此示例中,当编译器在函数模板中看到对 sum 的调用时,它似乎只查找在调用点已声明的名为 sum 的函数。当您切换顺序时,您这样做是为了使可变参数和永远不能调用一元

但实际上,事实要复杂得多。C 标准要求一种俗称“两阶段查找”的行为。这意味着:

    < li >当编译器看到函数模板的定义时,它会查找到目前为止已经声明的所有名为< code>sum的函数,并且 < li >当编译器稍后实例化函数模板时,它使用参数相关查找来查找< code>sum的其他重载,而不管它们是在封闭模板之前还是之后声明的。
 类似资料:
  • 我正在为64位mips机器使用gcc编译器。我注意到生成的一段汇编代码很有趣。下面是详细信息: 通常,bnez将立即跳到0xb0。但在0xb0之后的块中,我确信程序必须使用a1作为参数。但是我们可以看到,在0xb0之后,a1从未出现在块中。 但是a1在0x58中使用,就在bnez(0x54)之后。 那么0x54和0x58指令有可能同时执行吗?超标量处理器通过同时将多条指令分派到处理器上的冗余功能单

  • 我发现以下错误: 错误:变量或字段“foo”声明为void 错误:“a”之前应为“)” 错误:在'b'之前预期')' 在函数“int main()”中:错误:“foo”未在此范围内声明

  • 实时代码模板的介绍 上图 Gif 演示为最好的介绍 Live Templates。 实时代码模板需要字符串前缀,如 Gif 演示中,在输入 sys 后生成一段输出语句,其中 sys 前缀是我自己设置的。 实时代码模板支持变量参数设置,如 Gif 演示中,在输入 temp1 的时候,后面自动也生成了一个 temp1,这是因为两者的变量名是一致的,所以我设置了一个变量值内容之后,相同变量值的内容也会跟

  • 如果我们不确定分类特征的性质,比如它们是名词性的还是序数的,我们应该使用哪种编码?顺序编码还是一个热编码?关于这个话题有没有明确的规定? 我看到很多人对没有方向的分类数据使用顺序编码。假设一个频率表: 有很多人更喜欢在这个专栏上做顺序编码。我非常想用一热编码。我对此的看法是,做序数编码会给这些颜色分配一些有序的数字,这意味着一个排名。而且没有排名第一。换句话说,我的模型不应该认为color_whi

  • 本文向大家介绍Jquery $.ajax函数外的一段代码的执行顺序,包括了Jquery $.ajax函数外的一段代码的执行顺序的使用技巧和注意事项,需要的朋友参考一下 今天遇到了一个很都疼的问题。在一个函数中调用了JQuery的异步函数$.ajax ,然后在$.ajax函数外之后又有一段Jquery 代码。每次都是在$.ajax之后的代码先执行。 在网上搜了许久 终于找到了原因。拿来和大家分享分享

  • Webstorm的模版功能非常强大,懒人必备。 File Templates:文件模版 使用“ctrl+shift+a”,搜索File Templates: 会打开如下窗口: 接下来以新建个kissy模块文件为例: 额外给模版注入变量 变量名可以自定义,以${变量名}$这样的格式出现。 接下来我们来新建个文件试试。 使用“alt+insert”,打开新建文件列表: 可以看到,已经出现了“kissy