【问题标题】:Is a specialization implicitly instantiated if it has already been implicitly instantiated?如果特化已经被隐式实例化,它是否会被隐式实例化?
【发布时间】:2018-09-06 09:39:20
【问题描述】:

标题中的问题很清楚。更具体地说,请考虑以下示例:

#include <type_traits>

template <typename T>
struct is_complete_helper {
    template <typename U>
    static auto test(U*)  -> std::integral_constant<bool, sizeof(U) == sizeof(U)>;
    static auto test(...) -> std::false_type;
    using type = decltype(test((T*)0));
};

template <typename T>
struct is_complete : is_complete_helper<T>::type {};

// The above is an implementation of is_complete from https://stackoverflow.com/a/21121104/5376789

template<class T> class X;

static_assert(!is_complete<X<char>>::type{}); 
// X<char> should be implicitly instantiated here, an incomplete type

template<class T> class X {};

static_assert(!is_complete<X<char>>::type{}); // #1

X<char> ch; // #2

此代码compiles with GCC and Clang

根据[temp.inst]/1

除非类模板特化已被显式实例化或显式特化,否则当在需要完全定义的对象类型的上下文中引用该类模板特化或当类类型的完整性时,将隐式实例化类模板特化影响程序的语义

X&lt;char&gt; 被隐式实例化,因为static_assert(!is_complete&lt;X&lt;char&gt;&gt;::type{}) 会生成不完整的类型。

然后,在X 的定义之后,#1 表明X&lt;char&gt; 没有再次实例化(仍然不完整),而#2 表明X&lt;char&gt; 确实再次实例化了(成为一个完整的类型)。

如果一个特化已经被隐式实例化,它是否会被隐式实例化?为什么#1#2 有区别?

欢迎对标准进行解释。

【问题讨论】:

  • IIRC,这打破了 odr。
  • @YSC 你的意思是#1 和#2 打破了 odr 吗?但它是如此普遍,以至于一个专业化被多次引用......
  • 我错了,如果涉及多个 TU,就会破坏 odr,根据 [temp.point]/8。
  • 我认为该程序的 NDR 格式不正确,因为 is_complete&lt;X&lt;char&gt;&gt;::type 取决于实例化点(包括 EOF 之一)。
  • @Jarod42 - EOF 仅用于函数。类只有一个 POI。

标签: c++ templates language-lawyer template-instantiation implicit-instantiation


【解决方案1】:

如果一个特化已经被隐式实例化,它是否被隐式实例化?

没有。根据[temp.point]/8

类模板的特化在翻译单元内最多有一个实例化点。

x&lt;char&gt; 只需要实例化一次,而不是在第一个静态断言中命名时,只在ch 之前。但是,[temp.point]/8 也说

函数模板的特化,成员函数模板, 或类模板的成员函数或静态数据成员 在翻译单元中有多个实例化点,并且 除了上述实例化点之外,对于任何 这种特殊化在 翻译单元,翻译单元的结尾也被认为是一个 实例化点。 [...] 如果根据单一定义规则,两个不同的实例化点赋予模板特化不同的含义,则程序格式错误,无需诊断。

is_complete_helper::test 一个成员函数模板,它的声明在静态断言之前被实例化。所以它还必须在 TU 结束时有一个实例化。它可能会给出不同的结果。因此,此特征取决于格式错误的 NDR 构造。

【讨论】:

  • 那么是#2编译的bug吗?
  • @xskxzr - 错误在于假设is_complete 可以报告不同的事情。
  • 哦,我看到is_complete的问题了。但是为什么#2 会编译呢? X&lt;char&gt; 不是按照你的解释总是不完整的吗?
  • @xskxzr - 清理了我闲逛的烂摊子。现在清楚了吗?
  • @xskxzr - 必须尝试实例化该声明 (temp.inst/8) 才能使替换失败。虽然你提出了一个很好的观点。对于 [temp.point]/8 而言,它是否计算在内?我认为应该,但我没有找到任何结论。
猜你喜欢
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多