Alternative pattern for virtual template

Discussion in 'C++' started by GeeRay, May 5, 2009.

  1. GeeRay

    GeeRay Guest

    Hi all,
    I have this problem: I need to implement a class hierarchy where the
    main class has a template method that will be inherited by the subclass.
    Something like:

    class SuperClass
    {
    public:
    template<typename T>
    virtual void foo(const T& t) const = 0;
    }


    class SubClass: public SuperClass
    {
    public:
    template<typename T>
    virtual void foo(const T& t) const { cout << t << endl;}
    }

    Considering I know why it is not possible to make a template virtual, is
    there an alternative pattern to solve this kind of problems.

    Thanks in advance
    GeeRay, May 5, 2009
    #1
    1. Advertising

  2. GeeRay

    Neelesh Guest

    On May 5, 6:17 pm, GeeRay <> wrote:
    > Hi all,
    >         I have this problem: I need to implement a class hierarchy where the
    > main class has a template method that will be inherited by the subclass.
    > Something like:
    >
    > class SuperClass
    > {
    > public:
    >         template<typename T>
    >         virtual void foo(const T& t) const = 0;
    >
    > }
    >
    > class SubClass: public SuperClass
    > {
    > public:
    >         template<typename T>
    >         virtual void foo(const T& t) const { cout << t << endl;}
    >
    > }
    >
    > Considering I know why it is not possible to make a template virtual, is
    > there an alternative pattern to solve this kind of problems.
    >
    > Thanks in advance


    Making it a class template can solve the problem:

    template<class T> class SuperClass
    {
    public:
    virtual void foo(const T& t) const = 0;

    };

    template<class T> class SubClass: public SuperClass<T>
    {
    public:
    virtual void foo(const T& t) const { cout << t << endl;}
    //By the way, "virtual keyword isn't needed here

    };

    int main()
    {
    SuperClass<int> *s = new SubClass<int>();
    s->foo(10); //prints 10

    }
    Neelesh, May 5, 2009
    #2
    1. Advertising

  3. GeeRay

    GeeRay Guest

    Neelesh ha scritto:
    > On May 5, 6:17 pm, GeeRay <> wrote:
    >> Hi all,
    >> I have this problem: I need to implement a class hierarchy where the
    >> main class has a template method that will be inherited by the subclass.
    >> Something like:
    >> [...cut...]
    >> Thanks in advance

    >
    > Making it a class template can solve the problem:
    >
    > template<class T> class SuperClass
    > {
    > public:
    > virtual void foo(const T& t) const = 0;
    >
    > };
    >
    > template<class T> class SubClass: public SuperClass<T>
    > {
    > public:
    > virtual void foo(const T& t) const { cout << t << endl;}
    > //By the way, "virtual keyword isn't needed here
    >
    > };
    >
    > int main()
    > {
    > SuperClass<int> *s = new SubClass<int>();
    > s->foo(10); //prints 10
    >
    >



    The problem is that I would like to use the same method with different
    types:

    SuperClass * s = new SubClass();
    s->foo<int>(2);
    s->foo<const char*> ("foo");
    GeeRay, May 5, 2009
    #3
  4. GeeRay

    Noah Roberts Guest

    GeeRay wrote:
    > Hi all,
    > I have this problem: I need to implement a class hierarchy where the
    > main class has a template method that will be inherited by the subclass.
    > Something like:
    >
    > class SuperClass
    > {
    > public:
    > template<typename T>
    > virtual void foo(const T& t) const = 0;
    > }
    >
    >
    > class SubClass: public SuperClass
    > {
    > public:
    > template<typename T>
    > virtual void foo(const T& t) const { cout << t << endl;}
    > }
    >
    > Considering I know why it is not possible to make a template virtual, is
    > there an alternative pattern to solve this kind of problems.


    No. There are some things you can do but none of them generate the
    equivalent of virtual template functions. Simple fact is that the
    language doesn't support such a construct. How could it?

    I find that any time I'm tempted to do this, my design is not exactly
    correct.

    The closest you might come is to use NVPI and account for every possible
    argument to your template by hand:

    struct Base
    {
    // Document the concept:
    // T must be int or double.
    template < typename T >
    void f(T const& x);

    protected:
    virtual void do_f(double const& x) { ... }
    virtual void do_f(int const& x) { ... }
    };

    template < >
    void Base::f<double>(double const& x) { do_f(x); }
    template < >
    void Base::f<int>(int const& x) { do_f(x); }

    Basically you're doing what the compiler would have to magically do if
    it were to attempt supporting virtual template functions. As you can
    see, pretty much impossible without full and future knowledge of all
    calls to f<>(), which is why it isn't done.

    I'm sure you could make some preprocessor stuff to construct much of the
    above code, but you're still going to have to account for all possible
    types passed to your function.

    I'd suggest looking at alternative approaches.
    Noah Roberts, May 5, 2009
    #4
  5. GeeRay wrote:

    > class SuperClass
    > {
    > public:
    > template<typename T>
    > virtual void foo(const T& t) const = 0;
    > }
    >
    > class SubClass: public SuperClass
    > {
    > public:
    > template<typename T>
    > virtual void foo(const T& t) const { cout << t << endl;}
    > }
    >
    > Considering I know why it is not possible to make a template
    > virtual, is there an alternative pattern to solve this kind of
    > problems.


    If your higher-level goal is to ensure that the class does indeed
    have a certain function, perhaps you can equip its clients with Boost
    Concept Check.


    Martin

    --
    Quidquid latine scriptum est, altum videtur.
    Martin Eisenberg, May 5, 2009
    #5
  6. On 5 mai, 17:24, Noah Roberts <> wrote:
    > GeeRay wrote:
    > > Hi all,
    > > I have this problem: I need to implement a class hierarchy where the
    > > main class has a template method that will be inherited by the subclass.
    > > Something like:

    >
    > > class SuperClass
    > > {
    > > public:
    > > template<typename T>
    > > virtual void foo(const T& t) const = 0;
    > > }

    >
    > > class SubClass: public SuperClass
    > > {
    > > public:
    > > template<typename T>
    > > virtual void foo(const T& t) const { cout << t << endl;}
    > > }

    >
    > > Considering I know why it is not possible to make a template virtual, is
    > > there an alternative pattern to solve this kind of problems.

    >
    > No. There are some things you can do but none of them generate the
    > equivalent of virtual template functions. Simple fact is that the
    > language doesn't support such a construct. How could it?
    >
    > I find that any time I'm tempted to do this, my design is not exactly
    > correct.
    >
    > The closest you might come is to use NVPI and account for every possible
    > argument to your template by hand:
    >
    > struct Base
    > {
    > // Document the concept:
    > // T must be int or double.
    > template < typename T >
    > void f(T const& x);
    >
    > protected:
    > virtual void do_f(double const& x) { ... }
    > virtual void do_f(int const& x) { ... }
    >
    > };
    >
    > template < >
    > void Base::f<double>(double const& x) { do_f(x); }
    > template < >
    > void Base::f<int>(int const& x) { do_f(x); }
    >
    > Basically you're doing what the compiler would have to magically do if
    > it were to attempt supporting virtual template functions. As you can
    > see, pretty much impossible without full and future knowledge of all
    > calls to f<>(), which is why it isn't done.
    >
    > I'm sure you could make some preprocessor stuff to construct much of the
    > above code, but you're still going to have to account for all possible
    > types passed to your function.
    >
    > I'd suggest looking at alternative approaches.


    On of this approach is to use dynamic polymorphism, that is if you can
    define a same contract on your type. As an example if your foo is only
    displaying a message with the data in parameter, your contract if that
    the type should support (ostream<<T), you define the interface:

    struct foo_ostreamable
    {
    virtual ostream& output(ostream&)const=0;
    };

    Then you define a templated foo_streambable implementation:

    template<typename T>
    struct foo_ostreamable_imp: foo_ostreamable
    {
    T value;
    foo_ostreamable_imp(const T& t):value(t){}

    virtual ostream& output(ostream& os)const{return os<<value;}
    };

    And finally the parameter of SuperClass::foo with templated
    constructor:

    struct foo_param
    {
    template<typename T>
    foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));

    scoped_ptr<foo_ostreamable> data;
    };

    // foo_param can be written into ostream
    ostream& operator<<(ostream& os,const foo_param& p)
    {
    return p.data->output(os);
    }

    And finally, you define your classes:
    class SuperClass
    {
    public:
    virtual void foo(const foo_param&) const = 0;
    };

    class SubClass: public SuperClass
    {
    public:
    virtual void foo(const foo_param& p) const { cout << p <<
    endl;}
    } ;

    The compiler will automatically resolve with correct subtype:
    SubClass s;
    s.foo(1);
    s.foo(0.1);
    s.foo("bar");
    ....

    If you want to keep/compare foo_param values, there is some management
    to do such as deep copy and others to put it into canonical form. If a
    type doesn't react as you want, you overload foo_param constructor.

    There is an overhead but that depends on what you want.

    --
    Michael
    Michael Doubez, May 6, 2009
    #6
  7. GeeRay

    GeeRay Guest

    Michael Doubez ha scritto:
    > On 5 mai, 17:24, Noah Roberts <> wrote:
    >> GeeRay wrote:
    >>> Hi all,
    >>> I have this problem: I need to implement a class hierarchy where the
    >>> main class has a template method that will be inherited by the subclass.
    >>> Something like:
    >>> [cut]

    >
    > On of this approach is to use dynamic polymorphism, that is if you can
    > define a same contract on your type. As an example if your foo is only
    > displaying a message with the data in parameter, your contract if that
    > the type should support (ostream<<T), you define the interface:
    >
    > struct foo_ostreamable
    > {
    > virtual ostream& output(ostream&)const=0;
    > };
    >
    > Then you define a templated foo_streambable implementation:
    >
    > template<typename T>
    > struct foo_ostreamable_imp: foo_ostreamable
    > {
    > T value;
    > foo_ostreamable_imp(const T& t):value(t){}
    >
    > virtual ostream& output(ostream& os)const{return os<<value;}
    > };
    >
    > And finally the parameter of SuperClass::foo with templated
    > constructor:
    >
    > struct foo_param
    > {
    > template<typename T>
    > foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));
    >
    > scoped_ptr<foo_ostreamable> data;
    > };
    >
    > // foo_param can be written into ostream
    > ostream& operator<<(ostream& os,const foo_param& p)
    > {
    > return p.data->output(os);
    > }
    >
    > And finally, you define your classes:
    > class SuperClass
    > {
    > public:
    > virtual void foo(const foo_param&) const = 0;
    > };
    >
    > class SubClass: public SuperClass
    > {
    > public:
    > virtual void foo(const foo_param& p) const { cout << p <<
    > endl;}
    > } ;
    >
    > The compiler will automatically resolve with correct subtype:
    > SubClass s;
    > s.foo(1);
    > s.foo(0.1);
    > s.foo("bar");
    > ...
    >
    > If you want to keep/compare foo_param values, there is some management
    > to do such as deep copy and others to put it into canonical form. If a
    > type doesn't react as you want, you overload foo_param constructor.
    >
    > There is an overhead but that depends on what you want.
    >
    > --
    > Michael


    You're great!
    Thank you very much, that's exactly what I was looking for.

    -GR
    GeeRay, May 6, 2009
    #7
  8. GeeRay

    Guest

    Michael Doubez schrieb:
    [snipped original problem about the problem of combining virtual
    methods with templates]

    > On of this approach is to use dynamic polymorphism, that is if you can
    > define a same contract on your type. As an example if your foo is only
    > displaying a message with the data in parameter, your contract if that
    > the type should support (ostream<<T), you define the interface:
    >
    > struct foo_ostreamable
    > {
    > virtual ostream& output(ostream&)const=0;
    > };
    >
    > Then you define a templated foo_streambable implementation:
    >
    > template<typename T>
    > struct foo_ostreamable_imp: foo_ostreamable
    > {
    > T value;
    > foo_ostreamable_imp(const T& t):value(t){}
    >
    > virtual ostream& output(ostream& os)const{return os<<value;}
    > };
    >
    > And finally the parameter of SuperClass::foo with templated
    > constructor:
    >
    > struct foo_param
    > {
    > template<typename T>
    > foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));
    >
    > scoped_ptr<foo_ostreamable> data;
    > };
    >
    > // foo_param can be written into ostream
    > ostream& operator<<(ostream& os,const foo_param& p)
    > {
    > return p.data->output(os);
    > }
    >
    > And finally, you define your classes:
    > class SuperClass
    > {
    > public:
    > virtual void foo(const foo_param&) const = 0;
    > };
    >
    > class SubClass: public SuperClass
    > {
    > public:
    > virtual void foo(const foo_param& p) const { cout << p <<
    > endl;}
    > } ;
    >
    > The compiler will automatically resolve with correct subtype:
    > SubClass s;
    > s.foo(1);
    > s.foo(0.1);
    > s.foo("bar");
    > ...
    >
    > If you want to keep/compare foo_param values, there is some management
    > to do such as deep copy and others to put it into canonical form. If a
    > type doesn't react as you want, you overload foo_param constructor.
    >
    > There is an overhead but that depends on what you want.
    >
    > --
    > Michael


    That's a good explanation. Is this pattern named already?

    Stuart
    , May 6, 2009
    #8
  9. On 6 mai, 14:56, wrote:
    > Michael Doubez schrieb:
    > [snipped original problem about the problem of combining virtual
    > methods with templates]
    >
    >
    >
    > > On of this approach is to use dynamic polymorphism, that is if you can
    > > define a same contract on your type. As an example if your foo is only
    > > displaying a message with the data in parameter, your contract if that
    > > the type should support (ostream<<T), you define the interface:

    >
    > > struct foo_ostreamable
    > > {
    > > virtual ostream& output(ostream&)const=0;
    > > };

    >
    > > Then you define a templated foo_streambable implementation:

    >
    > > template<typename T>
    > > struct foo_ostreamable_imp: foo_ostreamable
    > > {
    > > T value;
    > > foo_ostreamable_imp(const T& t):value(t){}

    >
    > > virtual ostream& output(ostream& os)const{return os<<value;}
    > > };

    >
    > > And finally the parameter of SuperClass::foo with templated
    > > constructor:

    >
    > > struct foo_param
    > > {
    > > template<typename T>
    > > foo_param(const T& t){data.reset(new foo_ostreamable_imp<T>(t));

    >
    > > scoped_ptr<foo_ostreamable> data;
    > > };

    >
    > > // foo_param can be written into ostream
    > > ostream& operator<<(ostream& os,const foo_param& p)
    > > {
    > > return p.data->output(os);
    > > }

    >
    > > And finally, you define your classes:
    > > class SuperClass
    > > {
    > > public:
    > > virtual void foo(const foo_param&) const = 0;
    > > };

    >
    > > class SubClass: public SuperClass
    > > {
    > > public:
    > > virtual void foo(const foo_param& p) const { cout << p <<
    > > endl;}
    > > } ;

    >
    > > The compiler will automatically resolve with correct subtype:
    > > SubClass s;
    > > s.foo(1);
    > > s.foo(0.1);
    > > s.foo("bar");
    > > ...

    >
    > > If you want to keep/compare foo_param values, there is some management
    > > to do such as deep copy and others to put it into canonical form. If a
    > > type doesn't react as you want, you overload foo_param constructor.

    >
    > > There is an overhead but that depends on what you want.

    >
    > > --
    > > Michael

    >
    > That's a good explanation. Is this pattern named already?


    I think it is type erasure. It can be useful if you want virtual
    member function that takes any iterator of a given kind (let say an
    output iterator, it is easier to implement:) ) but are not too focused
    on performances (an indirection plus a virtual call per call, an
    allocation per copy , dynamic cast for comparison ...).

    The idea is taken from an article in Overload published by ACCU:
    http://accu.org/index.php/overloadonline

    I don't remember which issue (around end of year 2007 IIRC)

    --
    Michael
    Michael Doubez, May 6, 2009
    #9
  10. GeeRay

    Guest

    Michael Doubez wrote:
    > The idea is taken from an article in Overload published by ACCU:
    > http://accu.org/index.php/overloadonline
    >
    > I don't remember which issue (around end of year 2007 IIRC)


    Thanks again. Never heard of ACCU (I tried to look up what ACCU means,
    but their homepage doesn't say anything about this acronym).

    It seems that today is full of surprises (always a new thing to learn
    out there). Unfortunately, I can't access any articles on this page
    (it looks a bit amateurishly to me).

    Stuart
    , May 6, 2009
    #10
  11. GeeRay

    GeeRay Guest

    Michael Doubez ha scritto:
    > On 6 mai, 14:56, wrote:
    > The idea is taken from an article in Overload published by ACCU:
    > http://accu.org/index.php/overloadonline
    >
    > I don't remember which issue (around end of year 2007 IIRC)
    >
    > --
    > Michael
    >


    Good source.

    Thanks
    GeeRay, May 6, 2009
    #11
  12. On 6 mai, 17:14, wrote:
    > Michael Doubez wrote:
    > > The idea is taken from an article in Overload published by ACCU:
    > >http://accu.org/index.php/overloadonline

    >
    > > I don't remember which issue (around end of year 2007 IIRC)

    >
    > Thanks again. Never heard of ACCU (I tried to look up what ACCU means,
    > but their homepage doesn't say anything about this acronym).


    ACCU = Association of C and C++ Users

    But it is no longer C and C++ focused.

    > It seems that today is full of surprises (always a new thing to learn
    > out there). Unfortunately, I can't access any articles on this page


    Click on: "Go to the Overload Online archive"
    Issues are in PDF. somme of them are accessible in HTML format.

    --
    Michael
    Michael Doubez, May 7, 2009
    #12
  13. GeeRay

    Guest

    Michael Doubez wrote:
    > ACCU = Association of C and C++ Users
    >
    > But it is no longer C and C++ focused.
    >
    > Click on: "Go to the Overload Online archive"
    > Issues are in PDF. somme of them are accessible in HTML format.


    Gosh, I didn't see the forest for all the trees.

    Thanks again,

    Stuart
    , May 7, 2009
    #13
    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. Replies:
    4
    Views:
    365
    mlimber
    Jan 23, 2006
  2. Daniel Kay
    Replies:
    2
    Views:
    396
    dasjotre
    Sep 6, 2006
  3. Replies:
    2
    Views:
    541
  4. Markus Dehmann
    Replies:
    4
    Views:
    456
    Calum Grant
    Jul 25, 2008
  5. Trans
    Replies:
    5
    Views:
    100
Loading...

Share This Page