nested templates and partial specialization

Discussion in 'C++' started by ld, Nov 11, 2011.

  1. ld

    ld Guest

    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;
    }
    ld, Nov 11, 2011
    #1
    1. Advertising

  2. ld

    ld Guest

    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();
    }
    // -----
    ld, Nov 12, 2011
    #2
    1. Advertising

  3. ld

    Edek Guest

    On 11/12/2011 08:41 AM, ld wrote:
    > 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
    Edek, Nov 12, 2011
    #3
  4. ld

    ld Guest

    On Nov 12, 10:16 am, Edek <> wrote:
    > On 11/12/2011 08:41 AM, ld wrote:
    >
    > > 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).


    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.
    ld, Nov 12, 2011
    #4
  5. ld

    Edek Guest

    On 11/12/2011 12:33 PM, ld wrote:
    > On Nov 12, 10:16 am, Edek<> wrote:
    >> On 11/12/2011 08:41 AM, ld wrote:
    >>
    >>> 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).

    >
    > 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;
    }
    Edek, Nov 12, 2011
    #5
  6. ld

    Edek Guest

    On 11/12/2011 12:33 PM, ld wrote:
    > On Nov 12, 10:16 am, Edek<> wrote:
    >> On 11/12/2011 08:41 AM, ld wrote:
    >>
    >>> 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).

    >
    > 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;
    }
    Edek, Nov 12, 2011
    #6
  7. ld

    ld Guest

    On Nov 12, 1:52 pm, Edek <> wrote:
    > On 11/12/2011 12:33 PM, ld wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On Nov 12, 10:16 am, Edek<>  wrote:
    > >> On 11/12/2011 08:41 AM, ld wrote:

    >
    > >>> 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).

    >
    > > 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.


    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.

    >
    > 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;
    >
    >
    >
    >
    >
    >
    >
    > }
    ld, Nov 12, 2011
    #7
  8. ld

    ld Guest

    On Nov 12, 2:02 pm, Edek <> wrote:
    > On 11/12/2011 12:33 PM, ld wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > On Nov 12, 10:16 am, Edek<>  wrote:
    > >> On 11/12/2011 08:41 AM, ld wrote:

    >
    > >>> 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).

    >
    > > 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


    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.doit();
    >
    > }
    >
    > int main() {
    >    E<A, D> a;
    >    E<B<int>, D> b;
    >
    >
    >
    >
    >
    >
    >
    > }
    ld, Nov 12, 2011
    #8
  9. ld

    Edek Guest

    On 11/12/2011 02:07 PM, ld wrote:
    > 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;
    }
    Edek, Nov 12, 2011
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andriy Shnyr
    Replies:
    3
    Views:
    751
    Larry Evans
    Dec 4, 2003
  2. Shekhar
    Replies:
    1
    Views:
    469
    Alf P. Steinbach
    Apr 8, 2004
  3. JKop
    Replies:
    3
    Views:
    449
  4. Patrick Kowalzick
    Replies:
    0
    Views:
    798
    Patrick Kowalzick
    Oct 29, 2004
  5. VB
    Replies:
    2
    Views:
    438
Loading...

Share This Page