Reputation:
The N4296::14.7.1/1 [temp.inst]
provides the following example:
template<class T, class U>
struct Outer {
template<class X, class Y> struct Inner;
template<class Y> struct Inner<T, Y>; // #1a
template<class Y> struct Inner<T, Y> { }; // #1b; OK: valid redeclaration of #1a
template<class Y> struct Inner<U, Y> { }; // #2
};
Outer<int, int> outer; // error at #2
and the following explanation is given:
Outer<int, int>::Inner<int, Y>
is redeclared at#1b
. (It is not defined but noted as being associated with a definition inOuter<T, U>
.)#2
is also a redeclaration of#1a
. It is noted as associated with a definition, so it is an invalid redeclaration of the same partial specialization.
I was confused by the fact that #1b
is treated as a declaration, but not a definition. We explcitily provided the function body there, and why isn't it still a definition? In fact, couldn't you explain that exlnation.
Upvotes: 0
Views: 73
Reputation: 2373
A name is introduced into its scope with its first declaration and is then associated with an entity such as an object, function or class. In certain scopes, such as namespace scope or class scope, a name may be declared multiple times. A declaration of name may also include a definition of the named entity. After a definition is seen, it is said that the declaration in question is associated with a definition. No more than one definition is allowed for a named entity.
When a class template is instantiated implicitly, the definitions of its nested functions, classes and static object members are not instantiated immediately. They are only instantiated as soon as they are needed. However, there's a special rule to catch potential definition conflicts.
In this example, in a class template with two parameters, T
and U
, an inner class template with two parameters, X
and Y
, is declared. Two partial specializations are defined for the inner class, one for the case when X
coincides with T
and another for the case when X
coincides with U
. The first partial specialization is first declared at #1a and then redeclared and associated with a definition at #1b. The second partial specialization is declared and associated with a definition at #2.
So far so good.
But what if T
and U
are the same type, for example, int
? In such a case, for any given Y
, declarations in #1a, #1b, and #2 all declare the same name, Outer<int, int>::Inner<int, Y>
. Two of these declarations are associated with definitions and that causes conflict. The example in N4296 you quote is to demonstrate that the conflict must be diagnosed even though there are no references that require the instantiation of Outer<int, int>::Inner<int, Y>
.
Outer<int, char>
is fine because in this case T
and U
do not coincide and therefore the #2 gives definition to Outer<int, char>::Inner<char, Y>
which is different from Outer<int, char>::Inner<int, Y>
defined in #1b.
Upvotes: 0
Reputation: 385104
This is explained in the text immediately preceding the example!
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, 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. However, for the purpose of determining whether an instantiated redeclaration of a member is valid according to 9.2, a declaration that corresponds to a definition in the template is considered to be a definition.
There is a difference between the definition of the function that results from instantiating the templates, and a definition of the function templates themselves.
Upvotes: 3