Terms for creating a C ++ template

I wonder if anyone knows why the following two pieces of code behave differently. I can understand why the second one does not work, but why does the first one work? In the same place int x = gc.f(); the template must get an instance for the same error to occur, but why is there really no error?

a.cpp

 #include <iostream> using namespace std; template <typename T> struct A { struct B { }; }; template <typename T> struct C { typedef A<C<T> > D; int f() { typename D::B p; return 0; } }; C<float> gc; int x = gc.f(); template <typename T> struct A<C<T> > { struct B { B() { cout << "B::B()" << endl; } ~B() { cout << "B::~B()" << endl; } }; }; int main() { } 

Exit

 B::B() B::~B() 

and

a2.cpp

 #include <iostream> using namespace std; template <typename T> struct A { struct B { }; }; struct C { typedef A<C> D; int f() { D::B p; return 0; } }; C gc; int x = gc.f(); template <> struct A<C> { struct B { B() { cout << "B::B()" << endl; } ~B() { cout << "B::~B()" << endl; } }; }; int main() { } 

compiler error

 a2.cpp:24: error: specialization of 'A<C>' after instantiation a2.cpp:24: error: redefinition of 'struct A<C>' a2.cpp:6: error: previous definition of 'struct A<C>' 
+4
source share
3 answers

You are actually requesting two different things, although both are related to creating a template.

Why is the first part of the code compiling?

The standard states that the actual creation of the template is performed after processing the entire translation unit, which means that the actual creation of the template will be after all types defined in this translation unit are completed, even if the point instance is different and much earlier in the translation unit . More on this in this other question.

Why doesn't the second example compile?

The problem with the second example is that the standard requires that the template specialization be declared before the first use of this specialization.

Β§14.7.3p6 (C ++ 03)

If a template, a member template, or a member of a class template is explicitly specialized, then this specialization must be declared before the first use of this specialization, which will lead to an implicit implementation, in each translation unit into which such use occurs; no diagnostics required.

Please note that there are two different concepts. The instantiation point refers to where the instance is created in the code, and not when it is created. In your example, the instantiation point is the expression C<float> gc; , whereas, as in all other cases, after processing the entire transfer unit.

+3
source

You just need to remove the unnecessary typename qualifier and change things a bit. As the error message says, you have specialized A<C> after it was created in C To fix this, you can move the specialization A<C> to the definition of C , and then forward declare C to get rid of the undeclared identifier error.

Here's the fixed code:

 #include <iostream> using namespace std; template <typename T> struct A { struct B { }; }; struct C; // Forward declaration of C template <> struct A<C> { struct B { B() { cout << "B::B()" << endl; } ~B() { cout << "B::~B()" << endl; } }; }; struct C { typedef A<C> D; int f() { D::B p; return 0; } }; C gc; int x = gc.f(); int main() { } 
+2
source

Because typename used only to indicate types within a template.

+1
source

Source: https://habr.com/ru/post/1398929/


All Articles