即使从未实例化参考变量主模板,也需要对其进行初始化吗?

时间:2018-11-28 19:12:21

标签: 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

     

除非已明确实例化或明确指定了变量模板特化,否则使用特化时会隐式实例化变量模板特化。

     

...

     

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

     

14.7.2

     

除内联函数外,声明类型应从其初始值设定项或返回值(7.1.6.4)推导,const文字类型的变量,引用类型的变量和类模板专门化,显式实例化声明具有抑制引用实体隐式实例化的作用。 [注:目的是,作为显式实例化声明的主题的内联函数在odr-use(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

1 个答案:

答案 0 :(得分:8)

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

  

...该程序格式不正确,无需进行诊断,如果:

     
      
  • 如果模板中的语句或constexpr的子语句未实例化,则无法为该模板或constexpr的子语句生成有效的专业化名称。
  •   

您编写的参考模板永远不会产生有效的专业化名称,因为实例化产生的变量将始终需要初始化程序。


我提供的引文来自C ++ 17,但是C ++ 14中有类似的声明。