c++ - 为什么 C++03 要求模板参数有外部链接?

标签 c++ templates

背景

在 C++03 中,用作模板参数的符号必须具有外部链接;正如 this previous question 中所探讨的,此限制在 C++11 中已删除。 :

In C++03, template arguments could not have internal linkage:

[C++03: 14.6.4.2/1]: For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.
  • For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.

[..]

这在 C++11 中已更改(问题 #561: "Internal linkage functions in dependent name lookup"):

[C++11: C.2.6]: 14.6.4.2
Change: Allow dependent calls of functions with internal linkage
Rationale: Overly constrained, simplify overload resolution rules.

导致:

[C++11: 14.6.4.2/1]: For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
  • For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.

[..]

(找出缺少的“与外部链接” 限定条件。)

Issue #561 ("Internal linkage functions in dependent name lookup") ,导致在 C++11 中删除限制的提议,要求:

Furthermore, is it really necessary to exclude internal linkage functions from the lookup? Doesn't the ODR give implementations sufficient latitude to handle this case without another wrinkle on name lookup?

后面的答案:

The consensus of the group was that [..] internal-linkage functions should be found by the lookup (although they may result in errors if selected by overload resolution).


问题

限制的最初实际理由是什么?

似乎一定有一个,因为最初的标准措辞已将查找限制为具有外部链接的符号。

仅仅是“[internal-linkage functions] 如果通过重载解决方案选择可能会导致错误”,并且通过 2000 年代的观点转移了这有多重要?还是其他地方发生了变化,也许是其他地方针对不同 C++11 特性的新措辞的间接后果?

最佳答案

我怀疑它与 C++98 中臭名昭著的 export 模板特性有关。想想看。一旦您允许模板定义出现在单独的翻译单元中,但在指定模板参数(即模板被实例化)之前仍然不能真正编译,您就进入了这个暮光区,其中带有模板定义的 TU 和具有实例化的 TU 必须遵守链接器可见性规则(即分离模型),同时在重载解析方面共享它们的上下文。该问题的解决方案是在依赖名称查找中只允许具有外部链接的函数。

这是一个例子。导出模板的鲜为人知的“功能”之一是,您可以在模板的 TU 中拥有一些具有内部链接的函数或类(即,标记为 static 或在未命名的命名空间中)。如果具有实例化的 TU 也具有内部链接功能,该功能会与模板 TU 中的功能不明确或可能被取代怎么办?这是一个有点超现实的问题,我知道,这是导出模板的奇异世界。避免非常令人惊讶的行为的唯一方法是从查找中排除所有内部链接函数。还要考虑到没有人清楚地知道如何实际实现导出的模板,如果没有这个限制,实现起来可能会更加不可能。

因此,一旦导出的模板被淘汰,对依赖名称查找的限制似乎显然没有用,并且在没有太多争论的情况下就被取消了。至少,这对我来说是完全合理的,但是,当然,这是猜测。

这是一个具体的例子:

// in exptemp.h
export template <typename T> bool is_valid(T value);

// in exptemp.cpp
namespace {
  bool is_space(char c) {
    return (c == ' ') || (c == '\t');
  };
};

template <typename T>
bool is_valid(T value) {
  return is_space(value);
};

// in test.cpp
#include "exptemp.h"

namespace {
  bool is_space(char c) {
    return (c == ' ') || (c == '\t') || (c == '\n');
  };
};

int main() {
  char c = '\n';
  return is_valid(c);   // will this return 0 or 1 ?!?!?
};

关于c++ - 为什么 C++03 要求模板参数有外部链接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14597463/

相关文章:

c++ - 在 C++ 中将非常量引用传递给右值

c++ - Qt 中的 SFML 2.1 小部件

c++ - 如何使类成员变量与函数模板的返回类型相同?

c++ - 对变量的标准结构数组进行排序

c++ - 模板特化和继承

c++ - 可变参数子集

c++ - 未找到架构 x86_64 的符号隐含类型转换不起作用

c++ - 参数列表中的可选 "name"?

c++ - 减少模板标题的大小

带有 u8、char8_t 和 std::string 的 C++20