0

The code:

#include <iostream>

template<int N>
struct A
{
    int a = A<1>::a;
};


int main() { }

Is invalid for CLANG, but valid for GCC. What behavior is actually correct? The Standard wasn't pretty clear about that:

N4296::14.7.1/1 [temp.inst]

Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), the class template specialization is implicitly instantiated when the specialization is referenced in a context that requires a completely-defined object type or when the completeness of the class type affects the semantics of the program.

1 Answers1

5

This is invalid code, because A<1> has incomplete type at the point of usage. Your quote from the standard is not relevant (A<1> cannot be instantinated at the point of usage).

The situation would be different if instead you had

template<int> struct A;
template<> struct A<1> { static int a; };
template<> struct A<2>
{
  int a=A<1>::a;                    // fine: A<1> has complete type
};

Moreover, in your original code, what do you think that the value of A<1>::a or A<0>::a should be? Nowhere is there a way to assign a value to it. You claim that gcc compiles this, but what's A<1>:a? garbage? null?


As R Sahu pointed out in the comments, your code also suffers from the fact that you cannot access the member A<1>::a without an object (unless it's a static member).


Regarding the access to members.

In the code referred to by your comment, the member was accessed implicitly as member of the object *this. Thus within class A<1> (or any derived classes), A<1>::a is the same as this->a. But outside you must provide an object.

Walter
  • 44,150
  • 20
  • 113
  • 196
  • 1
    You can't do that unless `A::a` is a static member variable. – R Sahu Feb 27 '15 at 19:38
  • @RSahu Not quite clear why. We're getting access inside the initializer of the non-static member. –  Feb 28 '15 at 05:20
  • The RHS of the initialization statement cannot be `A<1>::a` unless `a` is a static data member of `A<1>` or `A<1>` is a parent class of `A<2>`. – R Sahu Feb 28 '15 at 05:25
  • @RSahu But in any way, `Within the class member-specification, the class is regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes).` So the class type is complete at the point if usage, isn't it? –  Feb 28 '15 at 05:27
  • @RSahu Moreover it's possible to use non-statics data member in the way I cited in my post. Look at [this](http://coliru.stacked-crooked.com/a/7c06cb1d2910e348) . I'm confused... –  Feb 28 '15 at 05:34
  • @DmitryFucintv, I don't have an answer to the first question. Regarding using `A::b` in your example, that is same as `int a = b;` since the statement is inside the class. When you have explicitly specialized `A<1>`, `A<1>::a` can be used by `A<2>` only if `A<1>::a` is a static member of `A<1>` or `A<1>` is super-class of `A<2>`. I think you know that. – R Sahu Feb 28 '15 at 05:58