I just found that when it comes to templates this code compiles in g++ 3.4.2 and works unless m() is not called:
template <typename T>
class C
{
T e;
public:
C(): e(0) {};
void m()
{
e = 0;
};
};
Now one may create and use instance
C<const int> c;
Until c.m() is not called there are no compile errors but is this legal?
Yes, this is legal. The template specification is that until a method is instantiated, it doesn't exist and therefor is not checked by the compiler. Here's the relevant bit from the spec:
14.7.1 - Implicit instantiation
-9- An implementation shall not implicitly instantiate a function
template, a member template, a
non-virtual member function, a member
class or a static data member of a
class template that does not require
instantiation.
Related
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
template<>
template<>
void A<int>::C<int>::show(){ //#1
}
int main(){
}
Consider the above code, At #1, it's an explicit specialization definition for member of member class template. Some rules will be applied to it as the following specified:
temp.expl.spec#5
A member of an explicitly specialized class is not implicitly instantiated from the member declaration of the class template; instead, the member of the class template specialization shall itself be explicitly defined if its definition is required. In this case, the definition of the class template explicit specialization shall be in scope at the point at which the member is defined. The definition of an explicitly specialized class is unrelated to the definition of a generated specialization. That is, its members need not have the same names, types, etc. as the members of a generated specialization. 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.
Firstly, what's explicitly specialized class? Does it refer to the entity which has explicit specialization declaration? It seems to it doesn't mean it, please look at the example in Explicitly specialized class part
template<> template<> class A<int>::B<double>;
According to that example, A<int> within the explicit specialization for member can be called a explicitly specialized class. So, In my first example A<int> and C<int> are all explicitly specialized class? I'm not sure. I feel the phrase explicitly specialized class is not clear in this section.
Please note the emphasized part, it means the enclosing class template explicit specialization shall appear in the same scope as that of explicit specialization definition for its member. The member is defined in global scope but there's no any explicit specialization definition for A<int> or C<int> that appears in the global scope. How to interpret this?
By the way, as a opposite example:
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
template<>
template<typename U>
struct A<int>::C{ //#2
void show();
};
template<>
template<typename U>
void A<int>::C<U>::show(){ //#3
}
int main(){
}
why such code is required an explicit specialization for class template C before #3, what's the difference between such two examples?
Explicitly specialized class
The phrase "explicitly specialized class" is unclear in this section,
temp.expl.spec#15
A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a template<> for each enclosing class template that is explicitly specialized.
[ Example:
template<class T1> class A {
template<class T2> class B {
void mf();
};
};
template<> template<> class A<int>::B<double>;
template<> template<> void A<char>::B<char>::mf();
— end example ]
what's the explicitly specialized class mean, Is it refer to an entity that have a explicit specialization declaration or something others? It seems to no explicit specialization for A<int> in the above example.
There is no confusion there, you have to parse those statements (C++ and English) according to their grammatical structure. Source code is description of program in language understandable for humans. Programming language is a tool of human cooperation.
CWG529 removed need to understand intuitively by changing wording to explain order and content of template-ids.
Here you declared template of class A with template parameter T, which contains class B and a nested declaration of template class C with template parameter U, which contains a method show():
template<class T> struct A {
struct B { };
template<class U> struct C {
void show();
};
};
Here you declared, that for explicitly specialized template class A (which required to have it declared first) with T = int that there is a template class C which contains method show()
template<>
template<typename U>
struct A<int>::C{ //#2
void show();
};
This declaration doesn't contradict previous one, but because it's a specialization of class A, it may expand it! You can do this:
template<>
template<typename U>
struct A<int>::C{ //#4
void hide();
};
Which means that for any A with T=int, there is a template class C that got member hide(). But other A's will have template class C with member show(). What previous statement did that it removed any doubts about content of C for this A's specialization.
Now this only defines member function show() for all C's contained in A<int>:
template<>
template<typename U>
void A<int>::C<U>::show(){ //#3
}
You don't have an explicit specialization of C here, which is an enclosing class for show(). the memeber id show() is preceded by an unspecialized template-id template<typename U> ... C<U>. There is only a definition of member function but it requires a visible declaration of that template C - the #2 part. The visibility may be attained by various means and "the scope" mentioned is generalized description of it.
Omitting part #2 would be a semantic equivalent of writing:
class C;
void C::show() { // ill-formed - C is an incomplete type.
}
We would know that all of A's contain some class C, but we don't have a complete definition for that particular C in specialized A<int> (and it may be different).
This statement actually states that specialization C<int>nested in specialization A<int> contains show()
template<>
template<>
void A<int>::C<int>::show(){ //#1
}
Any possibility of contradiction, ambiguity or uncertainty (aside from undefined behavior) are leading to ill-formed code and rules are meant to form the framework of limitations against which the code should be checked. With absence of #2, the #3 at some point could be followed by #4, then the #3 statement would become illegal and thus it is deemed as such. #2 and #4 at same time would be two definitions of same thing which also leads either to ill-formed code if they are present in same unit, or they would lead to undefined behavior if they are present in separate units within program.
The following is invalid code:
struct foo {
struct bar;
bar x; // error: field x has incomplete type
struct bar{ int value{42}; };
};
int main() { return foo{}.x.value; }
This is quite clear, as foo::bar is considered incomplete at the point where foo::x is defined.
However, there seems to be a "workaround" which makes the same class definition valid:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
int main() { return foo{}.x.value; }
This works with all major compilers.
I have three questions about this:
Is this indeed valid C++ code, or just a quirk of the compilers?
If it is valid code, is there a paragraph in the C++ standard that deals with this exception?
If it is valid code, why is the first version (without template) considered invalid? If the compiler can figure out the second option, I don't see a reason why it wouldn't be able to figure out the first one.
If I add an explicit specialization for void:
template <typename = void>
struct foo_impl {};
template<>
struct foo_impl<void> {
struct bar;
bar x; // error: field has incomplete type
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
int main() { return foo{}.x.value; }
It once again fails to compile.
The real answer might be ¯\_(ツ)_/¯, but it's probably currently okay because templates are magical, but it may be more explicitly not okay pending some other core issue resolutions.
First, the main problem of course is [class.mem]/14:
Non-static data members shall not have incomplete types.
This is why your non-template example is ill-formed. However, according to [temp.point]/4:
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
Which suggests that foo_impl<void>::bar is instantiated before foo_impl<void>, and hence it's complete at the point where the non-static data member of type bar is instantiated. So maybe it's okay.
However, core language issues 1626 and 2335 deal with not-exactly-the-same-but-still-quite-similar issues regarding completeness and templates, and both point to desiring to make the template case more consistent with the non-template case.
What does all of this mean when viewed as a whole? I'm not sure.
I think this example is explicitly allowed by
17.6.1.2 Member classes of class templates [temp.mem.class]
1
A member class of a class template may be defined outside the class template definition in which it is declared.
[Note: The member class must be defined before its first use that requires an instantiation (17.8.1) For example,
template<class T> struct A {
class B;
};
A<int>::B* b1; // OK: requires A to be defined but not A::B
template<class T> class A<T>::B { };
A<int>::B b2; // OK: requires A::B to be defined
—end note ]
This should work fine too:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
};
template<typename T>
struct foo_impl<T>::bar{ int value{42}; };
using foo = foo_impl<>;
int main()
{
return foo{}.x.value;
}
More details about the accepted answer
I am not sure that the accepted answer is the correct explanation, but it is the most plausible one for now. Extrapolating from that answer, here are the aswers to my original questions:
Is this indeed valid C++ code, or just a quirk of the compilers? [ It is valid code. ]
If it is valid code, is there a paragraph in the C++ standard that deals with this exception? [ [temp.point]/4 ]
If it is valid code, why is the first version (without template) considered invalid? If the compiler can figure out the second option, I don't see a reason why it wouldn't be able to figure out the first one. [ Because C++ is weird - it handles class templates differently than classes (you could have probably guessed this one). ]
Some more explanations
What seems to be happening
When instantiating foo{} in main the compiler instantiates an (implicit) specialization for foo_impl<void>. This specialization references foo_impl<void>::bar on line 4 (bar x;). The context is within a template definition so it depends on a template parameter, and the specialization foo_impl<void>::bar is obviously not previously instantiated, so all the preconditions for [temp.point]/4 are fulfilled, and the compiler generates the following intermediate (pseudo)code:
template <typename = void>
struct foo_impl {
struct bar;
bar x; // no problems here
struct bar{ int value{42}; };
};
using foo = foo_impl<>;
// implicit specialization of foo_impl<void>::bar, [temp.point]/4
$ struct foo_impl<void>::bar {
$ int value{42};
$ };
// implicit specialization of foo_impl<void>
$ struct foo_impl<void> {
$ struct bar;
$ bar x; // bar is not incomplete here
$ };
int main() { return foo{}.x.value; }
About specialization
As per [temp.spec]/4:
A specialization is a class, function, or class member that is either instantiated or explicitly specialized.
so the call to foo{}.x.value in the original implementation with templates qualifies as a specialization (this was something new to me).
About the version with explicit specialization
The version with explicit specialization does not compile as it seems that:
if the context from which the specialization is referenced depends on a template parameter
no longer holds, so the rule from [temp.point]/4 does not apply.
I'll answer the third part of your question - as IANALL (not a language lawyer).
The code is invalid for the same reason it's invalid to use a function before it has been declared - even though the compiler can figure out what the function's supposed to be by going further down in the same translation unit. And the cases are similar also in the sense that if you happen to have just a declaration with no definition, that's good enough for the compiler, while here you happen to have a template definition before the instantiation.
So the point is: The language standard mandates that the compiler does not look ahead for you when you want to define something (and a class template is not a definition of a class).
Consider the following template class
template<typename T>
struct Caller {
void func(const T &t) { t.func(); }
void gunc(const T &t) { t.gunc(); }
};
Now let some class Target only provide the member function func() but not gunc(), i.e.
struct Target {
void func() const { /* ... /* }
};
is the template instantiation Caller<Target> valid?
GCC, clang as well as VC++ accept such template instantiations. Of course, calling Caller<Target>::gunc() leads to an error but Caller<Target>::func() works just fine and as intended.
Now the question: What is the background for this permissive behavior and where are the relevant paragraphs in C++ standard.
It's specified in the standard, under Templates (14), Template instantiation and specialization (14.7), Implicit instantiation (14.7.1).
3 Unless a function template specialization has been explicitly
instantiated or explicitly specialized, the function template
specialization is implicitly instantiated when the specialization is
referenced in a context that requires a function definition to exist.
And
11 An implementation shall not implicitly instantiate a function
template, a member template, a non-virtual member function, a member
class, or a static data member of a class template that does not
require instantiation.
I (vaguely) know that a template is not instantiated if it is not used. For example, the following code will compile fine even though T::type doesn't make sense when T = int.
template<typename T>
struct A
{
void f() { using type = typename T::type; }
};
A<int> a; //ok
It compiles because f() is not used, so it is not instantiated — thus the validity ofT::type remains unchecked. It doesn't matter if some other member function g() calls f().
template<typename T>
struct A
{
void f() { using type = typename T::type; }
void g() { f(); } //Is f() still unused?
};
A<int> a; //ok
This also compile fines. But here I realize the vagueness in my understanding of the definition of "use". I ask:
Is f() still unused? How exactly?
I can clearly see it being used inside g(). But then I thought since g() is not used, f() is not used either, from instantiation point of view. That seems reasonable enough. so far.
However if I add virtual keyword to g(), it doesn't compile:
template<typename T>
struct A
{
void f() { using type = typename T::type; }
virtual void g() { f(); } //Now f() is used? How exactly?
};
A<int> a; //error
It results in compilation error because now it attempts to instantiate f(). I don't understand this behavior.
Could anybody explain this? Especially the impact of virtual keyword on the definition of "use" of member of class template.
A quick look at 3.2 [basic.def.odr] yields:
3/ [...] A virtual member function is odr-used if it is not pure. [...]
And I also found at 14.7.1 [temp.inst]:
10/ An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated. (emphasis mine)
So... I would say it is likely that a virtual method will always be instantiated.
In pragmatic terms, I would expect a compiler to instantiate the virtual table of a template class when it instantiates the class; and thus immediately instantiate all virtual member functions of this class (so it can references those from the virtual table).
Consider the following example:
template <typename T>
class A {
public:
void f() {
cout << "A::f()\n";
}
};
template<>
class A<int> {
};
template<typename T>
class B: public A<T> {
public:
void g() {
cout << "B::g()\n";
A<T>::f();
}
};
int main() {
B<int> b; // (1)
b.g(); // (2)
return 0;
}
Obviously the call to A::f() inside B::g() will fail for int template type. My question is at what point does the call fail? At (1) or (2)? I thought it should be (1) because at that point the compiler creates a new class with the template type int and compiles it. That compilation should fail in f() correct?
It will fail at (2), and this is guaranteed by the standard. In section 14.7.1/1, it says instantiating a template class does not instantiate it's members definitions. That will only happen once the member is used.
If you remove (2) from the code, it will compile.
14.7.1/1 excerpt:
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, static data members and member templates; and it causes the implicit instantiation of the definitions of member anonymous unions.
Emphasis mine.
Visual Studio's diagnosis is misleading. It will say see reference to class template instantiation 'B<T>' being compiled. What it means is not "I'm failing at the instantiation of B<T>", but "I'm failing at instantiating a member of the class B<T>"
It fails at 2). Member function of templates are instantiated when called.
More precisely: When a class template is instantiated, the declaration of its member functions are instantiated, but not their definition. The definition is instantiated when the function is used.