C++ 即使从未实例化引用变量主模板,也需要初始化它吗?

C++ 即使从未实例化引用变量主模板,也需要初始化它吗?,c++,templates,language-lawyer,clang++,variable-templates,C++,Templates,Language Lawyer,Clang++,Variable Templates,在C++14中声明引用模板而不初始化主引用模板是否合法,只要它从未实例化 template<class T> const T& ref; template<> auto ref<int> = 1; auto x = ref<int>; 初始化主引用模板没有任何意义,因为在实例化之前,它是一个模板,而不是引用 我发现我可以做如下事情: template<class T> const T& ref = "Meaning

在C++14中声明引用模板而不初始化主引用模板是否合法,只要它从未实例化

template<class T>
const T& ref;

template<>
auto ref<int> = 1;

auto x = ref<int>;
初始化主引用模板没有任何意义,因为在实例化之前,它是一个模板,而不是引用

我发现我可以做如下事情:

template<class T>
const T& ref = "Meaningless initialization with any value of any type";

template<>
auto ref<int> = 1;

auto x = ref<int>;
那么,问题是,为什么引用模板会有所不同?为什么引用模板的主声明必须是带有引用初始化的定义,而其他模板则不是这样

template<class T> const T& ref;      // Declaration, not definition
template<> const int& ref<int> = 1;  // Specialization definition
const int& iref = ref<int>;          // Specialization instantiation
模板常数T&ref;//声明,而不是定义
模板常数int&ref=1;//专门化定义
常数int&iref=ref;//专门化实例化

我相信[temp.res]/8中包含了这一点:

。。。如果出现以下情况,程序格式不正确,无需诊断:

  • 如果模板中的语句未实例化,则无法为模板或constexpr的子语句生成有效的专门化
您编写的引用模板永远不会产生有效的专门化,因为实例化生成的变量始终需要初始值设定项



我提供的引文来自C++17,但在C++14中有一个类似的语句。

变量声明是一个定义,除非它是用
extern
关键字声明的。如果您指的是一个声明,那么可以表示为:
template extern const T&ref。外部人员不会更改链接。这是一个变量模板的声明,而不是一个变量的声明。评论可能更迂腐、更笼统,更不容易访问:我不相信规则适用于这里。首先,14.6讨论的是模板定义内部的名称解析,我们这里不讨论--
const T&
不引用模板定义之外的任何名称。其次,
ref
在引用
ref
模板的唯一位置生成有效的专门化。将实例化
ref
专门化。程序中没有对
ref
模板的引用,该模板在查找时无法实例化。这就是为什么GCC不关心是否定义了主模板,因为它永远不需要实例化。@leek如果我们定义了一个函数模板和
const T&ref出现在正文中?你能理解为什么编译器会拒绝它吗?你问题中的情况也一样。由于引用需要初始化,这种语句可能被视为语法错误。正如我告诉@Oliv的,这是一个变量模板声明,而不是变量声明。用你的类比,如果你声明
模板void foo(T)
作为函数模板声明(不是函数声明),然后专门化
模板void foo(int x){}
,无需定义主函数模板来实例化和调用
foo()。模板不是对象/函数/类型,因此它们的声明/定义规则与对象、函数或类型不同。在隐式或显式实例化之前,它们只是模板。
template void foo(T){const T&ref;}
在GCC上编译得很好,但在Clang上编译得不好,原因可能与OQ相同。这是一个函数模板定义,不是函数定义。在实例化之前,
const T&ref
在没有初始值设定项的情况下出现的事实与标准的一种解释(GCC似乎使用)无关。在引用模板的情况下,它变得比本例更重要,因为我们可能需要没有默认定义的专门化,这对于类模板、函数模板和非ref变量模板是合法的。@leek No,您误解了标准中的“不能为模板生成有效的专门化”. 这意味着通过实例化模板产生的专门化是无效的。明确的专门化并不重要。
// Class
template<class T> class foo;        // Declaration, not definition
template<> class foo<int> {};       // Specialization definition
using ifoo = foo<int>;              // Specialization instantiation

// Function
template<class T> void bar(T);      // Declaration, not definition
template<> void bar(int) {}         // Specialization definition
void (*barp)(int) = bar<int>;       // Specialization instantiation

// Variable
int j;
template<class T> T* point;         // Declaration, not definition
template<> int* point<int> = &j;    // Specialization definition
int *k = point<int>;                // Specialization instantiation
template<class T> const T& ref;      // Declaration, not definition
template<> const int& ref<int> = 1;  // Specialization definition
const int& iref = ref<int>;          // Specialization instantiation