13

在 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

除非变量模板特化已被显式实例化或显式特化,否则变量模板特化在使用特化时被隐式实例化。

...

实现不应隐式实例化......一个不需要实例化的变量模板......。

14.7.2

除了内联函数、从其初始化程序或返回值 (7.1.6.4) 推导出的类型的声明、const文字类型的变量、引用类型的变量和类模板特化之外,显式实例化声明具有抑制实体的隐式实例化的效果他们所指的。[注意:目的是作为显式实例化声明主题的内联函数在使用odr(3.2)时仍将被隐式实例化,以便可以考虑将主体内联,但没有外联副本内联函数的一部分将在翻译单元中生成。—尾注]

14.7.3

显式特化的函数模板、类模板或变量模板的声明应在显式特化的声明之前。[注意:需要声明,但不需要模板的定义。——尾注]。

编辑添加:

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

类模板、变量模板和函数模板可以在不提供主要定义的情况下声明,仅提供专门化定义。以下代码在 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
4

1 回答 1

8

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

...程序格式错误,不需要诊断,如果:

  • 不能为模板或模板中的 constexpr if 语句的子语句生成有效的特化,并且模板未实例化...

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


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

于 2018-11-28T19:18:28.267 回答