another c++ q (with specialization and inheritance )

another c++ q (with specialization and inheritance )

Oleg Goldshmidt pub at goldshmidt.org
Tue Apr 28 16:03:35 IDT 2009


Erez, 

None of this is Linux-specific, maybe you should find a good C++
forum, e.g., comp.lang.c++.moderated? However, since you asked, here
is an explanation.

You should understand the difference between definition and
declaration, and also that if you define a template, then instantiate
an object of the templatized class, and then try to specialize the
template it will look as a redefinition of the class to the compiler.

See below.

Erez D <erez0001 at gmail.com> writes:

> i am having problems compiling the following code:
> ====================================
> #if 1
> template <class T> class c1 {};
> template <class T> class c2 : public c1<T> { public: c2(T &a); };

This is a *definition* of class c2<T>. Below you attempt to redefine
it (rather than specialize it - this is because you instantiate it
before specializing), and the compiler complains.

> #else
> template <class T> class c1;
> template <class T> class c2;

This is a forward declaration of class c2<T>. It is declared but not
yet defined. When this preprocessor branch is active the definition
below is OK.
  
> #endif
> template <> class c1<int>
> {
>         int m_a;
>         public:
>         c1():m_a(0) {};
>         c1(int a):m_a(a) {};
>         c1(int &a):m_a(a) {};
>         void set(const int a) {m_a=a;};
>         const int get(void) const {return m_a;};

The first const is ignored since you are not returning a const
value. The trailing ";" is also ignored (a recurring thing in your
code). But this is irrelevant for the question at hand...
 
>         c2<int> gen_c2(int a)
>         {
>                 c2<int> ret(a);

This is where you *instantiate* an object of type c2<int>, so you
cannot specialize the template later, as the compiler tells you.

The cure also is logical. Declare the method here, and write the
definition *after* specialization, i.e., put

c2<int> c1<int>::gen_c2(int a)
{
	c2<int> ret(a);
	return ret;
}

immediately before main().
 
>                 return ret;
>         }
>         const c1<int> &operator=(const c1<int> &other) {set(other.get());
> return *this;};
> };
> template <> class c2<int> : public c1<int>
> {
> public:
>         c2(int &a):c1(a) {};

I don't think this will compile (when you get to it) - c2 does not
have a c1 member, which is what this notation exists for. Instead,
c1(a) will be automatically called as the base class constructor, so
you only need

          c2(int &a) {}

if I understand your intention correctly.

> };
> int main()
> {
>         c1<int> a;
>         c2<int> b=a.gen_c2();

There is no c2<int> c1<int>::gen_c2(void). There is only c2<int>
c1<int>::gen_c2(int).

> }
> ===========================================
> if i compile it, i get:
> file.cpp:27: error: specialization of ‘c2<int>’ after instantiation

This is a precise statement - you only had to look for instantiation
in your code - see above.

> if on the other hand i change the #if 1 to #if 0, i get:
> file.cpp: In member function ‘c2<int> c1<int>::gen_c2(int)’:
> file.cpp:20: error: return type ‘struct c2<int>’ is incomplete

Correct again - you have declared, but not defined c2<T>.

Hope it helps,

-- 
Oleg Goldshmidt | pub at goldshmidt.org



More information about the Linux-il mailing list