2

我正在学习强制模板实例化。
它有效,但我仍然很好奇:-

#include <iostream>
#include <string>
template <typename T, T>struct NonTypeParameter { };//#1#
int lala=0;
template <typename T> class InitCRTP{
    public: static int init;
    public: using dummy=NonTypeParameter<int&, init>;   //#2#
};
template <typename T> int InitCRTP<T>::init = lala++;
class WantInit : public InitCRTP<WantInit>{
};
int main(){
    std::cout << lala << std::endl;
}

它打印 1,因为InitCRTP<WantInit>::init已正确实例化。

观察

  1. 如果我删除该行#2#,它将打印 0。(InitCRTP<WantInit>::init未实例化)。
  2. 如果我#2#从更改int&int,我将得到:-

    错误:'InitCRTP::init' 的值在常量表达式中不可用

  3. 如果我改变#1#totemplate <T>struct NonTypeParameter { };#2#topublic: using dummy=NonTypeParameter<init>;我会得到:-

    错误:“T”尚未声明

问题

  1. 为什么这条线#2#足以强制实例化?
    在我看来,它只是模板类中的一个 typedef,任何人都无法访问。

  2. 为什么我需要int&作为另一个模板参数才能使其可编译?
    一个可能更正确的问题:该技术的名称是什么?

原始帖子:使用 CRTP 强制显式模板实例化

4

1 回答 1

4

为什么 #2# 行足以强制实例化?

为了提供第二个参数,编译器必须绑定一个引用。这意味着它 ODR-使用静态变量,因此该变量必须存在并且具有唯一的标识。因此,它的定义是实例化的。

当您使用 plainint时,第二个参数只能接受整数常量表达式。非常量静态不能在常量表达式中使用。

为什么我需要int&作为另一个模板参数才能使其可编译?

您需要为第二个参数声明引用的类型,以获得编译器可以检查的类型。好吧,在 C++17 之前,无论如何你都需要这样做。现在我们可以使用占位符类型来代替。

template <auto&>struct NonTypeParameter { };//#1#
using dummy=NonTypeParameter<init>;//#2#

这将 ODR 使用传入的静态,而无需显式指定引用类型。

于 2019-09-16T07:25:37.677 回答