通过 typedef template<typename T, T> 强制模板实例化 - 为什么它有效?

Force template instantiation via typedef template<typename T, T> - why it works?

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

#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,我将得到:-

    error: the value of 'InitCRTP::init' is not usable in a constant expression

  3. 如果我将 #1# 更改为 template <T>struct NonTypeParameter { }; 并将 #2# 更改为 public: using dummy=NonTypeParameter<init>; 我将得到 :-

    error: 'T' has not been declared

问题

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

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

原文post:Force explicit template instantiation with CRTP

Why the line #2# is enough to force instantiation?

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

当你使用plain int时,第二个参数只能接受整型常量表达式。非常量静态不能用于常量表达式。

Why do I need int& as another template parameter to make it compilable?

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

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

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