【问题标题】:gcc fails with template recursion, while clang does notgcc 模板递归失败,而 clang 没有
【发布时间】:2014-09-03 13:51:49
【问题描述】:

比较clang 3.4.2和gcc 4.9,下面的代码哪个正确?

#include <iostream>

template<typename T>
struct SelfRec {
    static const int value = SelfRec<T>::value;
};

int main() {
    std::cout << SelfRec<int>::value << std::endl;
    return 0;
}

clang 打印 0,gcc 给出典型的达到模板最大深度错误。

【问题讨论】:

标签: c++ templates recursion clang gcc4.9


【解决方案1】:

这样的代码可能是什么意思?您说 Clang 打印 0,考虑到它已编译,这并不令人震惊,但零是什么意思?它是从哪里来的?

请注意,static const int value 不是全局静态变量,而是存在于每个 T 中。并且Ts 有无数个,所以 value 确实应该永远递归。我不怪 GCC 编译失败,事实上它可能是最好的。

【讨论】:

  • “而且Ts 的数量是无限的,所以价值确实应该永远递归。”这是一个奇怪的表述。如果value0 初始化,然后我们添加了static constexpr const int* addr = &amp;SelfRec&lt;T&gt;::value;,那会不会也“永远递归”?
  • @LucDanton:您认为类中的SelfRec&lt;T&gt;::value 是指指代分配给它的相同值的值吗?我可以买那个...尽管即使使用-Winit-self,Clang 仍然喜欢该代码,我愚蠢地希望它会产生一些诊断...但它没有(-Wall -Wextra 也没有)。我的阅读是 SelfRec&lt;T&gt; 还没有定义,所以必须定义,它是无限递归的。但似乎 Clang 足够“聪明”,可以解码这个谜题并发出常数零(考虑到未分配静态规则的唯一合理值)。
  • 以这种方式提及当前的专业化确实是可能的。例如。您可以将复制构造函数声明为SelfRec(SelfRec const&amp;);SelfRec(SelfRec&lt;T&gt; const&amp;);,它们的含义相同。可以加using self_type = SelfRec&lt;T&gt;;等等。
  • 完全明智地拒绝代码并不是崩溃。
【解决方案2】:

根据 § 14.7.2/15,这是未定义的行为:

15 有一个实现定义的数量,指定 限制递归实例的总深度,这可以 涉及多个模板。无限递归的结果 实例化未定义。

所以我同意 user657267 的任何一个编译器都可以“正确”。我从hacker news 得到了答案,虽然我使用的是标准的 n3337。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 2021-08-14
    • 1970-01-01
    • 2017-03-05
    • 2014-06-29
    • 2016-10-22
    相关资源
    最近更新 更多