【问题标题】:CRTP pattern doesn't trigger full template instantiationCRTP 模式不会触发完整的模板实例化
【发布时间】:2020-01-09 16:59:16
【问题描述】:

我创建了一个模板类,它在发生实例化时触发运行时文本输出:

template<typename T>
struct verbose {
    verbose()
    {
        std::cout << "Instantation occured!" << std::endl;
    }
};

template<typename T>
struct base
{
    inline static verbose<T> v;
};

当我强制创建实例化时,它会显示一个输出:

template struct base<int>;
//output: Instantation occured!

(Check on Wandbox).

另一方面,当我将它与 CRTP 模式一起使用时,似乎不会发生实例化:

class test : public base<test>
{
};

(Check on Wandbox)

这种行为符合 ISO 标准吗?我可以以某种方式强制进行实例化,而不需要我的模板类 (base) 的用户编写额外的代码吗?对我来说,重要的是静态变量构造函数的副作用。

【问题讨论】:

  • 当您说“实例化”时,您是指模板实例化还是创建对象的实例?因为您编写的代码是后者,而不是前者。在模板实例化期间无法获取消息,因为这是一个编译时过程,而不是运行时过程。
  • 你不能用静态断言得到消息
  • @NicolBolas 目的是在程序初始化期间获取消息,这在显式实例化 base&lt;int&gt; 时有效,但在执行 CRTP 时无效。见wandbox.org/permlink/yp5bGnsCTDcHMtrY
  • @Yamahari 不在有效程序中。如果您看到来自static_assert 的消息,则说明您的程序格式错误。
  • Odr 使用v(例如在析构函数或构造函数中)。

标签: c++ c++17 crtp


【解决方案1】:

您的 CRTP 使用属于隐式实例化:

当代码在上下文中引用需要完全定义类型的模板时,或者当类型的完整性影响代码时,并且该特定类型尚未显式实例化,就会发生隐式实例化。例如,当构造此类型的对象时,而不是构造指向此类型的指针时。

这适用于类模板的成员:除非该成员在程序中使用,否则不会实例化,并且不需要定义。
cppreference

在第二段之后,由于从未实际使用过base&lt;test&gt;::v,因此实际上不会发生base&lt;test&gt;::v 的实例化。

由于需要使用来生成其实例化,因此需要额外的代码来获得所需的输出。例如,您可以向base 添加一个构造函数:

template<typename T>
struct base
{
    inline static verbose<T> v;
    base() { (void)&v; }
};

仅此一项不足以根据test 的定义单独触发您的输出。然而,如果你的程序试图从test创建一个对象,那么构造函数的形成将导致模板的构造函数被使用,从而base&lt;test&gt;::v将被实例化。

【讨论】:

  • 因此,根据您的回答,我假设我必须要求“我的模板类(基础)的用户编写附加代码”。或者只是找到另一种方法来让我的班级用户变得懒惰;)
  • 如果您的班级用户实际上尝试从test 创建一个对象,那么您可以向base&lt;&gt; 添加一些内容以获取您的输出。答案已更新。
猜你喜欢
  • 1970-01-01
  • 2021-10-22
  • 2016-05-20
  • 1970-01-01
  • 1970-01-01
  • 2017-11-21
  • 1970-01-01
  • 2021-11-25
相关资源
最近更新 更多