nested templates and partial specialization

L

ld

Hereafter is a small code which reports my problem. gcc says

problem.cpp:43: error: invalid use of incomplete type ‘struct E<B<T>,
D>’
problem.cpp:3: error: declaration of ‘struct E<B<T>, D>’

Any hint? Thanks.

ld.

// type declaration
template <typename T, typename I>
struct E; // line 3

// abstract class
struct D {
virtual void doit() const = 0;
};

// partial specialization
template <typename T>
struct E<T, D> {
virtual void doit() const;

explicit E(T = T());
T& e;
};

// simple class
struct A {
void doit() const;
int a;
};

// template class
template <typename T>
struct B {
void doit() const;
T b;
};

// specialization with class, ok
template <>
void
E<A, D>::doit() const
{
e.doit();
}

// specialization with template class, error
template <> template <typename T>
void
E<B<T>, D>::doit() const // line 43
{
e.doit();
}

int main() {
E<A, D> a;
E<B<int>, D> b;
}
 
L

ld

If you prefer something running here are the same code with the
missing implementation defined and the faulty member function
specialization disabled unless -DFULLSPEC is provided. It works
because the purpose of the class E is to provide default
implementation of abstract classes using partial template
specialization, which can be more specialized by the final class if it
doesn't fit its needs. The real code is more complex, this is a
minimal example to reproduce the problem. Compiling and running with g+
+

$ g++ -std=c++98 -Wall -W -pedantic -O3 problem.cpp
$ ./a.out
A = 1
B = 2
$ g++ -std=c++98 -Wall -W -O3 problem.cpp -DFULLSPEC
problem.cpp:48: error: invalid use of incomplete type ‘struct E<B<T>,
D>’
problem.cpp:5: error: declaration of ‘struct E<B<T>, D>’

regards, ld

// ----- cut & paste below
#include <iostream>

// type declaration
template <typename T, typename I>
struct E;

// abstract class
struct D {
virtual void doit() const = 0;
};

// partial specialization
template <typename T>
struct E<T, D> : D {
virtual void doit() const { this->e.doit(); }

explicit E(T& e_) : e(e_) {}
T& e;
};

// simple class
struct A {
explicit A() : a(1) {}
void doit() const { std::cout << "A = " << a << std::endl; };
int a;
};

// template class
template <typename T>
struct B {
explicit B() : b(2) {}
void doit() const { std::cout << "B = " << b << std::endl; };
T b;
};

// specialization with class, ok
template <>
void
E<A, D>::doit() const
{
e.doit();
}

// specialization with template class, error
#ifdef FULLSPEC
template <> template <typename T>
void
E<B<T>, D>::doit() const // faulty line
{
e.doit();
}
#endif

int main() {
A a; B<int> b;
E<A, D> aa(a); aa.doit();
E<B<int>, D> bb(b); bb.doit();
}
// -----
 
E

Edek

template<> template<typename T>
void
E<B<T>, D>::doit() const // faulty line

Your notation is for

template<>
template<class T>
E<int, float>::doit<T>()
(or the other way round, I always forget if the outer
template is for the class or member).

Try

template<class T>
void E<B<T>, D>::doit() const

I didn't try compiling it... but it is supposed
to be a partial specialisation of E. Simpler case:

template <class T>
void fun<T*> () const

.... would match all pointers. You get the idea.

Edek
 
L

ld

Your notation is for

template<>
template<class T>
E<int, float>::doit<T>()
(or the other way round, I always forget if the outer
template is for the class or member).

The outer is for the class and the inner is for the class member but
in my case the two are for the class. You can remove safely the outer
template<>, it changes nothing to the problem. I remember that few
months ago somebody showed a similar problem and got an answer but I
cannot find it again. The answer was containing a use of template in
an uncommon place.

regards, laurent.
 
E

Edek

The outer is for the class and the inner is for the class member but
in my case the two are for the class. You can remove safely the outer
template<>, it changes nothing to the problem. I remember that few
months ago somebody showed a similar problem and got an answer but I
cannot find it again. The answer was containing a use of template in
an uncommon place.

The code posted below works, but you need a second E partial
specialisation explicitly. You would need the original
method specialised for <T,D> if you need direct T too.

I can't really understand why E<Something<some_T>, D> does not
match struct E<T,D> - which would be nice, and I assume which
is what you want.

Edek


// type declaration
template <typename T, typename I>
struct E; // line 3

// abstract class
struct D {
virtual void doit() const = 0;
};

// partial specialization
template <typename T>
struct E<T, D> {
virtual void doit() const;

explicit E(T = T());
T& e;
};

// 2nd partial specialisation
template <template<class> class Obj, class T>
struct E<Obj<T>, D> {
typedef Obj<T> TT;
virtual void doit () const;

explicit E(TT = TT());
TT&e;
};

// simple class
struct A {
void doit() const;
int a;
};

// template class
template <typename T>
struct B {
void doit() const;
T b;
};

// specialization with class, ok
template <>
void
E<A, D>::doit() const
{
e.doit();
}

// specialization with template class, error
template <template<class> class Wrap, class T>
void E<Wrap<T>, D>::doit() const // line 43
{
e.doit();
}

int main() {
E<A, D> a;
E<B<int>, D> b;
}
 
E

Edek

The outer is for the class and the inner is for the class member but
in my case the two are for the class. You can remove safely the outer
template<>, it changes nothing to the problem. I remember that few
months ago somebody showed a similar problem and got an answer but I
cannot find it again. The answer was containing a use of template in
an uncommon place.

Heh, it is much simpler: there is a subtle difference between
template<class T>
and
template<typename T>

The second one does not match B<T>, while the first one does. The
code below works too.

Edek

// type declaration
template <typename T, typename I>
struct E; // line 3

// abstract class
struct D {
virtual void doit() const = 0;
};

// partial specialization
template <class T>
struct E<T, D> {
virtual void doit() const;

explicit E(T = T());
T& e;
};

// simple class
struct A {
void doit() const;
int a;
};

// template class
template <typename T>
struct B {
void doit() const;
T b;
};

// specialization with class, ok
template <>
void
E<A, D>::doit() const
{
e.doit();
}

// specialization with template class, error NO ERROR NOW
template <class T>
void E<T, D>::doit() const // line 43
{
e.doit();
}

int main() {
E<A, D> a;
E<B<int>, D> b;
}
 
L

ld

The code posted below works, but you need a second E partial
specialisation explicitly. You would need the original
method specialised for <T,D> if you need direct T too.

I can't really understand why E<Something<some_T>, D> does not
match struct E<T,D> - which would be nice, and I assume which
is what you want.

Right. I cannot foresee all the use of E that i provide with default
implementations for I, while T is the user's class, (multi)templated
or not... I came up with your solution to solve the problem for some
specific cases but didn't succeed to generalize it for any T, and it
must be transparent for the users.

regards, laurent.
 
L

ld

Heh, it is much simpler: there is a subtle difference between
template<class T>
and
template<typename T>

The second one does not match B<T>, while the first one does. The
code below works too.

Edek

// type declaration
template <typename T, typename I>
struct E; // line 3

// abstract class
struct D {
   virtual void doit() const = 0;

};

// partial specialization
template <class T>
struct E<T, D> {
   virtual void doit() const;

   explicit E(T = T());
   T& e;

};

// simple class
struct A {
   void doit() const;
   int a;

};

// template class
template <typename T>
struct B {
   void doit() const;
   T b;

};

// specialization with class, ok
template <>
void
E<A, D>::doit() const
{
   e.doit();

}

// specialization with template class, error NO ERROR NOW
template <class T>
void E<T, D>::doit() const // line 43

But it is not anymore a specialization for B<T> but just T, that is
why it works. Assume that another class C<T> wants to specialize it
too. How does it make the difference? Moreover, in this case, typename
and class have the same meaning (not always the case though).

regards, laurent.
 
E

Edek

But it is not anymore a specialization for B<T> but just T, that is
why it works. Assume that another class C<T> wants to specialize it
too. How does it make the difference? Moreover, in this case, typename
and class have the same meaning (not always the case though).

Yes, right, sorry.

Actually I think you are trying a member specialisation by a weird
specialisation of the class (just the method, not whole class). It
works with sfinae, but not for virtual methods, and I am not sure
about partial class specialisations.

The below uses inheritance to get the example working - I don't know
if this fits your usage, but inheritance is one way of doing such
things.

Edek

// type declaration
template <typename T, typename I>
struct E; // line 3

// abstract class
struct D {
virtual void doit() const = 0;
};

template <class T, class TT> struct helper {
void doitInternal (T const&) const;
};


// partial specialization
template <class T>
struct E<T, D> : public helper<T,D> {
virtual void doit() const;

explicit E(T = T());
T& e;
};



// simple class
struct A {
void doit() const;
int a;
};

// template class
template <typename T>
struct B {
void doit() const;
T b;
};

// specialization with class, ok
template <>
void E<A, D>::doit() const
{
e.doit();
}

template <class T>
struct helper<B<T>, D> {
void doitInternal (B<T> const&) const;
};

template <class T>
void E<T, D>::doit() const
{
doitInternal(e);
}

template <class T, class TT>
void helper<T,TT>::doitInternal(T const&) const {}

template <class T>
void helper<B<T>, D>::doitInternal(B<T> const& e) const // line 43
{
// for B<T>
e.doit();
}



int main() {
E<A, D> a;
E<B<int>, D> b;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top