Implicit instantiation depending on scoped or unscoped enumeration - c++

14.7.3/6 says the following:
If a template, a member template or the member of a class template is explicitly specialized then that
specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.
It then gives the following example:
template<class T> struct A
{
enum E : T;
enum class S : T;
};
template<> enum A<int>::E : int { eint }; // OK
template<> enum class A<int>::S : int { sint }; // OK
template<class T> enum A<T>::E : T { eT };
template<class T> enum class A<T>::S : T { cT };
template<> enum A<char>::E : char { echar }; // ill-formed, A<char>::E was instantiated
// when A<char> was instantiated
template<> enum class A<char>::S : char { schar }; // OK
I'm not following how it is able to compile the last line but not the one before it. I expected both examples to fail because both A<char>::E and A<char>::S were being implicitly instantiated. I notice when I remove class from the enum-key of S in the primary template the last line fails with the same message as the other. Why does this happen?

Implicit instantiation of a class template implicitly instantiates the definitions of unscoped member enumerations, but only the declarations of scoped member enumerations.
§14.7.1 [temp.inst]/p1 (emphasis added):
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not of the
definitions, default arguments, or exception-specifications of the
class member functions, member classes, scoped member
enumerations, static data members and member templates; and it
causes the implicit instantiation of the definitions of unscoped
member enumerations and member anonymous unions.

Related

An Issue about the rule of explicit specialization where mentioned implicit instantiation

#include <iostream>
template<class T> struct A {
enum E : T;
};
template<class T> enum A<T>::E : T { eT };
template<> enum A<char>::E : char { //#1
echar
};
int main(){
}
Consider the above code which is mentioned in temp.expl.spec#6, it's a typically ill-formed code. The rule says:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.
At the point #1, where the specialization A<char> will cause implicit instantiation
As a contrast:
#include <iostream>
template<class T> struct A {
struct Test;
};
template<typename T>
struct A<T>::Test{
};
template<>
struct A<int>::Test{ //#2
int c;
};
int main(){
}
Consider this code, At the point #2, where the specialization A<int> also cause implicit instantiation, The difference of the implicit instantiation between such two codes is said as the following:
temp.inst#2
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions. However, for the purpose of determining whether an instantiated redeclaration is valid according to [basic.def.odr] and [class.mem], a declaration that corresponds to a definition in the template is considered to be a definition.
Because in the first code, the member enumeration is unscoped, hence the implicit instantiation of A<char> will also implicit instantiated the definition for enum E. As a contrast, in the second, Test is a member class, hence the implicit instantiation of specialization A<int> will only cause implicit instantiation of the declaration for member class Test rather than definition.
As a variant case of the first code:
#include <iostream>
template<class T> struct A {
enum E : T;
};
template<> enum A<char>::E : char {
echar
};
template<> enum A<int>::E : int { //#1
echar
};
int main(){
}
The difference from the first code is that there's no definition for member enumeration E of its enclosing primary class template, within the primary class template A, it's just a declaration.
So, I think the rule in [temp.expl.spec#6] is not clear. As these above codes shown, in each case, the specialization of primary class template all cause the implicit instantiation for class member, The distinction is one expect the implicit instantiation of declaration , the other is definition.
So, I think modified the rule as the following:
If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation of the definition that instantiated from the definition for the corresponding entity, in every translation unit in which such a use occurs; no diagnostic is required.
It will be conform the observable result. If I miss something, please correct me.

template<> for the explicit specialization of a member enumeration

According to 17.7.3 [temp.expl.spec] paragraph 5 (N4659),
... Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template.
The explicit specialization of E definitely does not belong to the bold case, and it still needs template<>. Why is that?
template<class T> struct A {
enum E : T;
};
template<> enum A<int>::E : int { eint };
This paragraph is related to members of an explicitly specialized class template, but you have not explicitly specialized the class template. This is an example of the case it is talking about:
template<class T> struct A {
enum E : T;
};
template<> struct A<int> {
enum E : int;
};
enum A<int>::E : int { eint }; // no template<> here
In your example code, you have explicitly specialized a member of the primary template, which does require using template<>, as specified in the first paragraph.
1 An explicit specialization of any of the following:
...
(1.7) — member enumeration of a class template
...
can be declared by a declaration introduced by template<>; that is:
explicit-specialization:
template < > declaration
The underlying principle behind paragraph 5 is that once you've explicitly specialized a template, it is no longer a template, and you work with the specialization just like you would any other non-template entity.

When a class template is instantiated, is a member template declaration also instantiated?

So let's take a example :
template<typename T> struct foo
{
template<typename X> void bar(void (T::*)()) {}
template<typename X> void bar(X*) {}
template<typename X> void bar(T**) {}
};
int main() { foo<int> p; }
Will above instantiation of class foo<int> instantiate member template declaration bar even though member itself is template? Any reference from standard will be much appreciated.
The answer is yes.
Citation from C++11 standard, [temp.inst] [14.7.1]:
...
The implicit instantiation of a class template specialization causes the implicit instantiation of the
declarations, but not of the definitions, default arguments, or exception-specifications of the class member
functions, member classes, scoped member enumerations, static data members and member templates; and
it causes the implicit instantiation of the definitions of unscoped member enumerations and member anonymous unions.
The second part has some more info about exactly when the member template definitions are instantiated. (It generally happens implicitly, when they are used:)
Unless a member of a class template or a member template has been explicitly instantiated or explicitly
specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated
side-effects) of a static data member does not occur unless the static data member is itself used in a way
that requires the definition of the static data member to exist.

Member class instantiation

N4296::14.7.1/1 [temp.inst] told us the following:
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not of the
definitions, [...], member classes, [...]
What is that rule about? Let me give you an example:
template<class T>
class A
{
public:
template<class W> class Y; //1, declaration
template<class V> class U{ V v; }; //2, definition
};
A<int> a; //3, implicit instantiation
int main(){ }
Does implicit instantiation at //3 cause implicit instantiation at //2 and at //1? If so, what template argument was used to instantiate those member classes?
There is nothing special about those member templates, compared to the "outer" template. The compiler reads them as a declaration, such that it knows that there exist names as A<T>::Y<W> and A<T>::U<V>, much the same as when you declare the template for class A:
template <typename T>
class A {
int a;
};
Which also only declares the existence of a class A<T> but does not instantiate it.
Instantiation is deferred until a templated type is actually used (or explicitly instantiated), which equally applies to the member templates.

static member initialization for specialized template class

class A
{
};
template <typename A, int S>
class B
{
public:
static int a[S];
B()
{
a[0] = 0;
}
};
template<> int B<A, 1>::a[1];
int main()
{
B<A, 1> t;
t;
}
It compiles under GCC 4.1, but does not link:
static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a'
I would prefer to keep initialisation specialised if it is possible, since the array holds some data specific to the type.
For static member specializations, if you don't initialize the member, it is taken as a specialization declaration, that just says "Oh, don't instantiate the member from the primary template, because there is a specialized definition somewhere else". It should be mentioned that the definition should appear in a .cpp file (otherwise, you will earn the opposite: multiple definitions), and the declaration without initializer should still be placed in the header file.
Now the correct syntax is indeed the following, and it should not appear in a header file, but in a .cpp file
template<> int B<A, 1>::a[1] = { };
The following should still appear in a header file:
template<> int B<A, 1>::a[1];
This will serve as the specialization declaration.
From this, it follows that you can't specialize a member that only has a default constructor and is not copyable, because you would need this syntax:
// needs a copy constructor!
template<> Type Class<Arguments>::member = Type();
C++0x fixes this:
// doesn't anymore need a copy constructor
template<> Type Class<Arguments>::member{};
For the Standardese people among us, here are the quotes:
14.7.3/6:
If a template, a member template or the member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.
14.7.3/15:
An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration. [Note: there is no syntax for the definition of a static data member of a template that requires default initialization.
template<> X Q<int>::x;
This is a declaration regardless of whether X can be default initialized (8.5). ]
3.2/3:
Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required.
3.2/5:
There can be more than one definition of a class type (clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (clause 14), non-static function template (14.5.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program [...]
The restriction of this to "for which some template parameters are not specified" means that we are allowed to do the following, placing it into a header (thus possibly having multiple definitions of this specialization):
template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;
In your case, you have all parameters specified, making it not being covered by the one defintion rule for allowing multiple definitions.
You need to actually assign a value to it.
template<> int B<A, 1>::a[1] = {0};
It does not link because you don't define a value to your static member.
template<> int B<A, 1>::a[] = { 0 };
Edit:
Btw: I would always prefer to use boost::array instead of native C-types:
class A { };
template <typename A, std::size_t S>
class B
{
public:
static boost::array<int, S> a;
B() { a[0] = 0; }
};
template<> boost::array<int, 1> B<A, 1>::a = { };
int main()
{
B<A, 1> t;
cout << t.a[0] << endl;
}