【问题标题】:Function template instantiation using an incomplete type使用不完整类型的函数模板实例化
【发布时间】:2016-05-20 03:13:17
【问题描述】:

以下 C++ 代码是否正确(不正确)?为什么?

class MyC;
class MyB {
public:
     template <class MyT> static void Gimme() { MyT(); }
     MyB() { Gimme<MyC>(); }
} B_;

class MyC  {
public: MyC() { }
};

g++ 4.7.2 不抱怨。

【问题讨论】:

  • 这是合法的,但这是标准中一个非常敏感的领域。比我有更多空闲时间的人可能能够拼凑所有相关部分。

标签: c++ templates language-lawyer incomplete-type


【解决方案1】:

我猜想 C++14 标准的以下部分在这里起作用

14.6.4.1 实例化点

8 函数模板、成员函数模板或类的成员函数或静态数据成员的特化 模板中可能有多个实例化点 翻译单元,除了实例化点 如上所述,对于任何具有以下意义的专业化 翻译单元内的实例化,翻译结束 unit 也被认为是一个实例化点。 [...]

(强调我的。)

请注意,与 C++11 相比,这部分文档在 C++14 中发生了显着变化。另请参阅DR#993,这似乎暗示将此类实例化简单地推迟到翻译单元的末尾是一种有效的实现技术。

即使 GCC 在-std=c++11 模式下接受它,我也会谨慎声明您的代码在 C++11 实例化规则下格式错误。

【讨论】:

  • 我没有听从你的解释 - 14.6.4.1/1 似乎说Gimme&lt;MyC&gt; 应该在MyB 的定义关闭后立即实例化。我看不到单元末尾的 附加 实例化点应该如何允许编译器忽略第一个这样的点。
  • @M.M:一方面,这是我自己并没有立即理解的事情。我没有明确要求 all 实例化点是否应该有效或仅 one 就足够了。另一方面,DR#993 似乎暗示一个实现可以简单地忽略所有“中间”实例化点,并在 TU 的最后实例化它。它将这称为“允许的实现技术”。去图...
  • 您需要将三个句子向前读入该段落: 如果两个不同的实例化点根据一个定义规则(3.2)赋予模板特化不同的含义,则程序是非良构的, 不需要诊断。 忽略除 TU 结束之外的所有其他实例化点是一种有效的实现技术,因为 不需要诊断 部分,但这并不能使代码运行良好-形成。抄送@MM
  • aschepler 的评论 (stackoverflow.com/questions/7210286/…) 怎么样?实例化点不是只有在这种情况下的类型已经完成后才起作用吗?
  • @bogdan:我已经读过了。我只是没有任何明确的措辞来解释在这种情况下“不同的含义”是什么意思。在所有点上,代码的语义都是明确的:表达式使用功能符号T() 执行转换。是否在其中某些点上具有类型 T 不完整是否有资格为相应的专业化赋予“不同的含义”......好吧,再一次,我在文档中的任何地方都没有看到对该问题的明确答案。跨度>
【解决方案2】:

是的,这是合法的 C++ 代码。您将MyC 声明为前向声明,稍后定义在同一范围内。并且因为 C++ 编译器使用至少 2 遍来解析源文件,所以这是正确的,并且会生成正确的机器代码。您的“不完整”类型MyC 并不完整。

【讨论】:

  • “使用至少 2 次传递来解析源文件”不是它在 C++ 中的工作方式。 C++ 对模板定义中的依赖名称有两阶段名称查找
  • @AnT:是的,你是对的。我只是稍微简化了一点;-) 但是 2 遍并没有错:首​​先是预处理器,然后是 c++ 解析(我知道,这与这个问题无关)......
猜你喜欢
  • 2021-10-22
  • 2017-11-21
  • 1970-01-01
  • 1970-01-01
  • 2013-07-02
  • 2019-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多