【问题标题】:Can internal linkage rule break a valid c++03 code in c++11?内部链接规则可以破坏 c++11 中的有效 c++03 代码吗?
【发布时间】:2026-01-11 02:20:05
【问题描述】:

如果c++03中有有效代码,c++11中是否会因为引入了内部链接规则而中断?

Clause C.2.6 Clause 14: templates point 3 14.6.4.2

我想不出任何例子。

感谢任何帮助。

【问题讨论】:

  • C++ 向后兼容,所以它应该是 IMO 的有效代码
  • 具有内部链接的模板实例化示例包括在未命名的命名空间中故意实例化的模板化函数(不是模板类的成员函数)。模板函数实例的内部链接永远不会隐式发生(即它们总是由程序员故意采取的行动产生的)。如果您有执行此操作的代码,那么与 C++03 相比,此规则可能会导致某些代码在 C++11 中的工作方式不同(将调用某些函数的不同重载)。但实际上,程序员很少有理由编写这样的代码。
  • @NutCracker 我明白了,但我看到“*.com/questions/23047198/…”和“*.com/questions/14595992/…”说代码由于内部链接而给出不同的输出。但它不是 c++03 中的有效代码,这就是为什么它不是有效的示例。
  • @Peter 我想不出前任。代码,因为在重载的情况下,肯定本地(内部链接)函数将具有更高的范围..那么我猜c ++ 03本身会出现错误或警告。
  • @NutCracker,有几个细节上的小角落案例,仅关注标准无法确保完全向后兼容性。但更重要的问题实际上是:编译器是否相应地向后兼容?对于现实世界的场景,这可能与非标准扩展使用的情况有关......

标签: c++ c++11


【解决方案1】:

作为参考,这是 §14.6.4.2 [temp.dep.candidate]“候选函数”的 C++03 版本:

对于依赖于模板参数的函数调用,如果函数名称是 unqualified-id 而不是 template-id,则使用以下方法找到候选函数通常的查找规则(3.4.1、3.4.2)除了:

  • 对于使用非限定名称查找 (3.4.1) 的查找部分,只能找到具有来自模板定义上下文的外部链接的函数声明。
  • 对于使用关联命名空间 (3.4.2) 的查找部分,只能找到在模板定义上下文或模板实例化上下文中找到的具有外部链接的函数定义。

如果调用格式错误或找到更好的匹配,则在关联命名空间中的查找会考虑所有翻译单元中这些命名空间中引入的具有外部链接的所有函数声明,而不仅仅是考虑在模板中找到的那些声明定义和模板实例化上下文,则程序具有未定义的行为。

您可以编写一些在 C++03 中定义良好但在 C++11 中没有定义的示例代码:

#include <iostream>

void print(short x) {
    std::cout << x;
}

static void print(long x) {
    std::cout << x;
}

template<typename T>
void print_twice(T x) {
    print(x);
    print(x);
}

int main() {
    print_twice(0);
    // C++03: `void print(long)` does not have external linkage so is not considered.
    //        Calls `void print(short)` twice
    
    // C++11: Both `void print(long)` and `void print(short)` are viable,
    //        but neither is better so it is ambiguous (compile time error)
}

(虽然 clang 和 gcc 似乎没有实现 C++03 版本的 ADL,所以至少在使用这些编译器编译时不会出现这种情况)

【讨论】:

  • 在 c++11 和 c++03 中出现相同的错误。 “错误:重载 'print(int&)' 的调用不明确”
  • @alearner 是的,因为大多数编译器从未正确实现这一点,并且标准已更改以匹配它们在 C++11 中实际执行的操作。学究式地,编译器是错误的,因为无法在 C++03 模式下编译它。