Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is initialization of a reference variable primary template required even when it is never instantiated?

Is it legal to declare a reference template in C++14 without initializing the primary reference template, as long as it is never instantiated?

template<class T>
const T& ref;

template<>
auto ref<int> = 1;

auto x = ref<int>;

This produces different results on GCC and 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.

It makes no sense having to initialize the primary reference template, because until it's instantiated, it's a template, not a reference.

I have found that I can do something like:

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

template<>
auto ref<int> = 1;

auto x = ref<int>;

because apparently GCC and Clang both accept but ignore the reference template initializer RHS as long as it's a valid expression and the primary reference template is never instantiated. And any expression of any type satisfies Clang's initialization requirement.

GCC does not require an initializer as long as the primary reference template is never instantiated. That seems to be the correct behavior "in spirit", because until a reference template is actually instantiated, it should not need an initializer.

The Standard isn't 100% clear on reference templates. Here's what little I could find on variable template instantiation:

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 ].

Edit to add:

A variable template declaration, class template declaration, or function template declaration, is not the same as a variable declaration, class declaration, or function declaration, respectively, and is not subject to the same rules. Until a template is instantiated, it is just a template.

Class templates, variable templates, and function templates may be declared without providing a primary definition, only specialization definitions. The following code is legal on both Clang and 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

The question, then, is why should it be any different for a reference template? Why should the primary declaration of a reference template have to be a definition with a reference initialization, when that's not true of any other templates?

template<class T> const T& ref;      // Declaration, not definition
template<> const int& ref<int> = 1;  // Specialization definition
const int& iref = ref<int>;          // Specialization instantiation
like image 681
leek Avatar asked Nov 28 '18 19:11

leek


1 Answers

I believe this is covered by [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...

The reference template you've written can never yield a valid specialization, as the variable produced by an instantiation will always require an initializer.


The quotation I provided is from C++17, but there's a similar statement in C++14.

like image 169
Brian Bi Avatar answered Sep 29 '22 08:09

Brian Bi