首页 > 解决方案 > “用作非类型模板参数”是否使函数模板隐式实例化?

问题描述

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

此代码是否有保证

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

标签: c++language-lawyerfunction-templatesnon-type-template-parameterimplicit-instantiation

解决方案


从 n4713

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

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

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

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

M<Test> m;

一次在翻译单元的末尾。

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

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

我怀疑这条规则背后的原因是让编译器可以自由地check立即实例化或推迟到稍后实例化。你不能依赖它实际实例化的两个点中的哪一个check


推荐阅读