“用作非类型模板参数”是否使函数模板隐式实例化?

zwh*_*nst 5 c++ language-lawyer function-templates implicit-instantiation non-type-template-parameter

我想编写一个M接受不完整类型C作为模板参数的类模板。但我也希望C在最终定义时具有一些特征。

此代码是否有保证

  • 编译如果定义(标志),
  • 如果 !defined(FLAG) 编译失败?
template <auto> struct Dummy {};

template <typename C>
void check()
{
    static_assert(std::is_trivial_v<C>);
}

template <typename C>
struct M : Dummy<&check<C>>
{
    //static_assert(std::is_trivial_v<C>);//error: incomplete type
    C * p;
};

struct Test;
M<Test> m;

int main()
{
    return 0;
}

#if defined(FLAG)
struct Test {};
#else
struct Test { std::string non_trivial_member; };
#endif
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 4

从 n4713 开始

实例化点 [temp.point] (17.7.4.1/8)

函数模板、成员函数模板或类模板的成员函数或静态数据成员的特化可以在翻译单元内具有多个实例化点,并且除了上述实例化点之外,对于任何此类模板当翻译单元内有一个实例化点的专业化时,翻译单元的末尾也被认为是一个实例化点。类模板的特化在翻译单元内至多有一个实例化点。任何模板的专门化都可能在多个翻译单元中具有实例化点。如果根据单一定义规则 (6.2),两个不同的实例化点赋予模板特化不同的含义,则该程序是格式错误的,无需诊断。

首先,请注意,主要模板是标准语言的专业化参数。根据我的经验,C++ 程序员使用它的方式与标准不同。

其次,check<Test>你的程序中有两个实例化点;一次在

M<Test> m;
Run Code Online (Sandbox Code Playgroud)

并在翻译单元的末尾一次。

check<Test>at的含义与翻译单元末尾M<Test> m的 的含义不同。check<Test>在一个地方Test是不完整的,在另一个地方是完整的。的身体check<Test>肯定有不同的含义。

所以你的程序格式不正确,不需要诊断。在您的情况下,格式不正确的程序恰好执行您想要的操作,但它可以(在标准下)编译为任何内容,或者无法编译。

我怀疑这条规则背后的原因是让编译器可以自由地立即实例化check或推迟实例化。不允许您依赖这两个点中的哪一个来实际实例化 的主体check