c++ - 即使从未实例化引用变量主模板,是否也需要对其进行初始化?

标签 c++ templates language-lawyer clang++ variable-templates

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

template<class T>
const T& ref;

template<>
auto ref<int> = 1;

auto x = ref<int>;

这会在 GCC 和 Clang 上产生不同的结果:

$ g++ -std=c++14 -c ref.cpp
$

$ clang -std=c++14 -c ref.cpp
ref.cpp:2:10: error: declaration of reference variable 'ref' requires an
      initializer
const T& ref;
         ^~~
1 error generated.

必须初始化主引用模板是没有意义的,因为在它被实例化之前,它是一个模板,而不是一个引用。

我发现我可以这样做:

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

template<>
auto ref<int> = 1;

auto x = ref<int>;

因为显然 GCC 和 Clang 都接受但忽略引用模板初始化程序 RHS,只要它是一个有效的表达式并且主引用模板永远不会被实例化。并且任何类型的任何表达式都满足 Clang 的初始化要求。

只要主引用模板从未实例化,GCC 就不需要初始化器。这似乎是“精神上”的正确行为,因为在实际实例化引用模板之前,它不应该需要初始化程序。

标准在引用模板上并不是 100% 明确的。以下是我在变量模板实例化方面能找到的一点点:

14.7.1

Unless a variable template specialization has been explicitly instantiated or explicitly specialized, the variable template specialization is implicitly instantiated when the specialization is used.

...

An implementation shall not implicitly instantiate ... a variable template ... that does not require instantiation.

14.7.2

Except for inline functions, declarations with types deduced from their initializer or return value (7.1.6.4), const variables of literal types, variables of reference types, and class template specializations, explicit instantiation declarations have the effect of suppressing the implicit instantiation of the entity to which they refer. [ Note: The intent is that an inline function that is the subject of an explicit instantiation declaration will still be implicitly instantiated when odr-used (3.2) so that the body can be considered for inlining, but that no out-of-line copy of the inline function would be generated in the translation unit.—end note ]

14.7.3

A declaration of a function template, class template, or variable template being explicitly specialized shall precede the declaration of the explicit specialization. [ Note: A declaration, but not a definition of the template is required. —end note ].

编辑添加:

变量模板声明、类模板声明或函数模板声明分别不同于变量声明、类声明或函数声明,并且不受相同规则的约束。在模板被实例化之前,它只是一个模板。

类模板、变量模板和函数模板可以在不提供主要定义的情况下声明,只提供专门化定义。以下代码在 Clang 和 GCC 上都是合法的:

// 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

最佳答案

我相信 [temp.res]/8 涵盖了这一点:

... The program is ill-formed, no diagnostic required, if:

  • no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated...

您编写的引用模板永远不会产生有效的特化,因为实例化产生的变量总是需要一个初始化器。


我提供的引用来自C++17,但C++14中有类似的说法。

关于c++ - 即使从未实例化引用变量主模板,是否也需要对其进行初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53526523/

相关文章:

c++ - 在 C++ 中使用方法作为变量

c++ - 从单链表中删除整个节点

c++ - 元编程传递值的类型应该在哪里?

c++ - 你怎么能确保一个 C++ 函数可以被调用为

c++ - 在 boost::asio 中清除来自串口的输入数据

templates - Azure DevOps 管道 : same template twice in one stage

javascript - 如何重定向到另一个页面并从表中传递 url 中的参数?

c++ - 表达式类型

c++ - 使用容器中元素的别名使用 std::list::remove 删除元素是否正确?

c++ - (a=1)=2 在 C++98 中是未定义的行为吗?