C++ Template Virtual Function

Discussion in 'C++' started by Vishal, Nov 30, 2012.

  1. Vishal

    Vishal Guest

    Hi,

    I have Class A and according to my requirements the implementation of
    the class is fixed. Class A manages the setting/getting of values.
    The values stored can be of type integer, unsigned integer, character,
    unsigned character and std::strings. The available types can grow in
    the future. I'm having trouble finding a manageable way of storing
    values of different types with the ability of retrieving them. The
    problem area is class B's getValue method. It can't be a virtual
    template method of a non template class. So, how should I provide a
    unified way for class A to get a list of all the stored values that
    match the tag value being passed?

    I don't need to have a class B and C. If there is a better way that
    only has one class, it's okay. I do want to avoid just having a bunch
    of switch statements that executes different code based on different
    types. This is what I think is unmanageable as new type are required.


    #include<list>


    class B
    {
    private:
    unsigned long m_Tag;

    public:

    B(unsigned long tag) : m_Tag(tag) {}

    template<typename T>
    virtual int getValue(std::list<T> &val) = 0;


    }; // end of class B


    template<typename T>
    class C : public B
    {
    private:
    T m_Value;

    public:
    C(unsigned long const& tag, T const& value) : B(tag) {
    m_Value = value;
    }

    virtual int getValue(std::list<T> &val) {
    val.push_back(m_Value);
    }

    }; // end of class C

    class A
    {
    private:
    std::list<B> m_Collection;

    public:
    template<typename T>
    setTagValue(unsigned long tag, T const& value) {
    m_Collection.push_back(C<T>(tag, value));
    }

    template<typename T>
    getTagValue(unsigned long const tag, std::list<T> values) {
    for(auto i = m_Collection.begin(); i != m_Collection.end(); i++) {
    if(i->getTag() == tag) {
    i->getValue(values);
    }
    }
    }


    }; // end of class A







    int main (void)
    {
    A collection;

    collection.setTagValue(2, "hello");
    collection.setTagValue(3, static_cast<int>(3));

    std::list<int> values;

    collection.getTagValue(3, values);
    };
    Vishal, Nov 30, 2012
    #1
    1. Advertising

  2. Vishal

    Vishal Guest

    On Dec 1, 2:18 am, Paavo Helde <> wrote:
    > Vishal <> wrote innews::
    >
    > > Hi,

    >
    > > I have Class A and according to my requirements the implementation of
    > > the class is fixed.  Class A manages the setting/getting of values.
    > > The values stored can be of type integer, unsigned integer, character,
    > > unsigned character and std::strings.  The available types can grow in
    > > the future.  I'm having trouble finding a manageable way of storing
    > > values of different types with the ability of retrieving them.  The
    > > problem area is class B's getValue method.  It can't be a virtual
    > > template method of a non template class.  So, how should I provide a
    > > unified way for class A to get a list of all the stored values that
    > > match the tag value being passed?

    >
    > There is no such thing as a virtual template function. This would require
    > recompiling all classes in the class hierarchy and adding vtable slots to
    > all classes whenever a new specialization happens to be called on *any*
    > class in the hierarchy. This would mean some serious whole program
    > analysis and would not probably work with DLL-s anyway.
    >
    > That said, it seems you are wanting some kind of type erasure feature. In
    > principle this means to store pointers to dynamically allocated instances
    > of different types in your container, and upon retrieval restore the type
    > somehow. This sounds similar to boost::any, maybe you can use this.
    >
    > > class A
    > > {
    > >     private:
    > >      std::list<B> m_Collection;

    >
    > You can't have a list of base class B objects here; when storing derived
    > C objects as B they would be sliced. That's why you need to store
    > pointers instead. The boost::any class encapsulates this pointer
    > mechanism AFAIK and hides such details from you.
    >
    > In any case, bear in mind that the template mechanisms are compile-time
    > only and cannot dispatch the execution based on information which becomes
    > available at run-time only. This probably means that if the run-time type
    > of the objects is determined by a "tag", then the tag must appear as a
    > template parameter in your interface, in order to avoid run-time switch
    > statements.
    >
    > hth
    > Paavo



    > There is no such thing as a virtual template function. This would require
    > recompiling all classes in the class hierarchy and adding vtable slots to
    > all classes whenever a new specialization happens to be called on *any*
    > class in the hierarchy. This would mean some serious whole program
    > analysis and would not probably work with DLL-s anyway.


    You are correct. I discovered the same thing when this didn't work.
    It was unfortunate.


    > That said, it seems you are wanting some kind of type erasure feature. In
    > principle this means to store pointers to dynamically allocated instances
    > of different types in your container, and upon retrieval restore the type
    > somehow. This sounds similar to boost::any, maybe you can use this.


    I'm familiar with boost::any. I had hoped to use it but couldn't
    figure out how to avoid the type cast exception failures if the wrong
    type was asked for. Since, I know that only one type will be correct
    I don't want the cost of throwing exceptions to find the correct
    type. I've ended up storing the type that was passed in so I could
    figure out which cast to use. This avoids my issue of using a wrong
    cast, but now I need a switch statement.

    //Example casting
    switch(a)
    {
    case: eType::float: cast here
    }


    > In any case, bear in mind that the template mechanisms are compile-time
    > only and cannot dispatch the execution based on information which becomes
    > available at run-time only. This probably means that if the run-time type
    > of the objects is determined by a "tag", then the tag must appear as a
    > template parameter in your interface, in order to avoid run-time switch
    > statements.


    I'm vaguely familiar with tag dispatching. How would you use tag
    dispatching with getValues<T>? Would this design fix the switch
    statement issue I discussed earlier? I would like to have a single
    place to add new types and not change A. Is that possible with tag
    dispatching?

    Thanks

    Vishal
    Vishal, Dec 3, 2012
    #2
    1. Advertising

  3. Vishal

    Vishal Guest

    On Dec 3, 9:42 am, Paavo Helde <> wrote:
    > Vishal <> wrote innews::
    >


    > I'm vaguely familiar with tag dispatching. How would you use tag
    > dispatching with getValues<T>? Would this design fix the switch



    I've have included an updated version of the example code that uses
    boost::any.

    >> It is not clear what do you want to achieve.


    B::getValue shows the "switch" like statement that I want to avoid
    needing to modify as new types are added.


    > How do you call getValues<T>? More specifically, how do you specify T when
    > calling it? How is T related to the type of the stored items?


    Class B::getValue shows how I'm relating my stored type with T. Can
    tag dispatch end my suffering?


    struct eType
    {
    enum Type {
    short,
    long
    char
    };
    };

    class B
    {
    private:
    unsigned long m_Tag;
    boost::any m_Value;
    eType::Type m_Type;

    protected:
    template<typename T>
    eType::Type getType(void) {
    if (boost::is_same<T, short>::value ) return eType::short;
    if (boost::is_same<T, long >::value ) return eType::long;
    if (boost::is_same<T, char >::value ) return eType::char;

    return eType::char; //Should never get to this return.
    }

    public:
    B(unsigned long tag, boost::any & value, eType::Type type)
    : m_Tag(tag)
    , m_Value(value)
    , m_Type(type)
    {
    BOOST_STATIC_ASSERT(boost::is_same<T, short>::value ||
    boost::is_same<T, long>::value || boost::is_same<T, char>::value);
    }

    template<typename T>
    int getValue(std::list<T> &val) {
    if ( m_Type == eType::short )
    val.push_back(boost::any_cast<short>(m_Value));
    if ( m_Type == eType::long ) val.push_back(boost::any_cast<long>
    (m_Value));
    if ( m_Type == eType::char ) val.push_back(boost::any_cast<char>
    (m_Value));

    return 0;
    }
    }; // end of class B


    template<typename T>
    class C : public B
    {
    public:
    C(unsigned long const& tag, T const& value) : B(tag, value,
    B::getType<T>()) {}
    }; // end of class C


    class A
    {
    private:
    std::list<B> m_Collection;

    public:
    template<typename T>
    setTagValue(unsigned long tag, T const& value) {
    m_Collection.push_back(C<T>(tag, value));
    }


    template<typename T>
    getTagValue(unsigned long const tag, std::list<T> values) {
    for(auto i = m_Collection.begin(); i != m_Collection.end(); i++) {
    if(i->getTag() == tag) {
    i->getValue(values);
    }
    }
    }
    }; // end of class A

    int main (void)
    {
    A collection;

    collection.setTagValue(3, static_cast<int>(3));

    std::list<int> values;

    collection.getTagValue(3, values);
    };
    Vishal, Dec 3, 2012
    #3
  4. Vishal

    Vishal Guest

    > The getType() method does not make much sense. It just translates from T
    > to the enum values. First, there is no reason for it to be a member
    > function of B. Second, there is an run-time dispatch which is not needed
    > as everything is known at compile-time. Typically, this kind of
    > translation is done by some kind of traits class (which typically
    > contains other useful stuff as well), e.g.:


    Thanks for the traits example. That makes sense.


    > In getValue(), it seems inner type m_Type is in no way related to the output type T.


    Not correct. The inner type is comparing it's value against the
    passed type.

    > If the types do not match, your code converts
    > the data, possibly truncating the values.


    If the types don't match the code doesn't add anthing to the passed
    list. So, how is the code converting data?


    > If you were able to guarantee that the client code always calls getValue
    > with the correct (matching) T, then it would be indeed trivial to write a
    > shorter version:
    >
    > template<typename T>
    > int getValue(std::list<T> &val) {
    >    val.push_back(boost::any_cast<T>(m_Value));
    >    return 0;
    >
    > }


    Since it's not guaranteed, couldn't we check the types with the tag
    dispatch like so?

    template<typename T>
    int getValue(std::list<T> &val) {
    if ( m_Type == getType<T>() )
    val.push_back(boost::any_cast<T>(m_Value));
    return 0;
    }
    Vishal, Dec 3, 2012
    #4
  5. Vishal

    Jeff Flinn Guest

    On 12/3/2012 12:08 PM, Vishal wrote:
    > On Dec 1, 2:18 am, Paavo Helde <> wrote:
    >> Vishal <> wrote innews::
    >>
    >>> Hi,

    >>
    >>> I have Class A and according to my requirements the implementation of
    >>> the class is fixed. Class A manages the setting/getting of values.
    >>> The values stored can be of type integer, unsigned integer, character,
    >>> unsigned character and std::strings. The available types can grow in
    >>> the future. I'm having trouble finding a manageable way of storing
    >>> values of different types with the ability of retrieving them. The
    >>> problem area is class B's getValue method. It can't be a virtual
    >>> template method of a non template class. So, how should I provide a
    >>> unified way for class A to get a list of all the stored values that
    >>> match the tag value being passed?

    >>
    >> There is no such thing as a virtual template function. This would require
    >> recompiling all classes in the class hierarchy and adding vtable slots to
    >> all classes whenever a new specialization happens to be called on *any*
    >> class in the hierarchy. This would mean some serious whole program
    >> analysis and would not probably work with DLL-s anyway.
    >>
    >> That said, it seems you are wanting some kind of type erasure feature. In
    >> principle this means to store pointers to dynamically allocated instances
    >> of different types in your container, and upon retrieval restore the type
    >> somehow. This sounds similar to boost::any, maybe you can use this.
    >>
    >>> class A
    >>> {
    >>> private:
    >>> std::list<B> m_Collection;

    >>
    >> You can't have a list of base class B objects here; when storing derived
    >> C objects as B they would be sliced. That's why you need to store
    >> pointers instead. The boost::any class encapsulates this pointer
    >> mechanism AFAIK and hides such details from you.
    >>
    >> In any case, bear in mind that the template mechanisms are compile-time
    >> only and cannot dispatch the execution based on information which becomes
    >> available at run-time only. This probably means that if the run-time type
    >> of the objects is determined by a "tag", then the tag must appear as a
    >> template parameter in your interface, in order to avoid run-time switch
    >> statements.
    >>
    >> hth
    >> Paavo

    >
    >
    >> There is no such thing as a virtual template function. This would require
    >> recompiling all classes in the class hierarchy and adding vtable slots to
    >> all classes whenever a new specialization happens to be called on *any*
    >> class in the hierarchy. This would mean some serious whole program
    >> analysis and would not probably work with DLL-s anyway.

    >
    > You are correct. I discovered the same thing when this didn't work.
    > It was unfortunate.
    >
    >
    >> That said, it seems you are wanting some kind of type erasure feature. In
    >> principle this means to store pointers to dynamically allocated instances
    >> of different types in your container, and upon retrieval restore the type
    >> somehow. This sounds similar to boost::any, maybe you can use this.

    >
    > I'm familiar with boost::any. I had hoped to use it but couldn't
    > figure out how to avoid the type cast exception failures if the wrong
    > type was asked for. Since, I know that only one type will be correct
    > I don't want the cost of throwing exceptions to find the correct
    > type. I've ended up storing the type that was passed in so I could
    > figure out which cast to use. This avoids my issue of using a wrong
    > cast, but now I need a switch statement.
    >
    > //Example casting
    > switch(a)
    > {
    > case: eType::float: cast here
    > }
    >
    >
    >> In any case, bear in mind that the template mechanisms are compile-time
    >> only and cannot dispatch the execution based on information which becomes
    >> available at run-time only. This probably means that if the run-time type
    >> of the objects is determined by a "tag", then the tag must appear as a
    >> template parameter in your interface, in order to avoid run-time switch
    >> statements.


    Have you watched the video of Sean Parent's boostcon/C++ Now talk at:

    http://www.youtube.com/watch?v=_BpMYeUFXv8&feature=plcp

    The recently accepted boost type erasure library by Steven Watanabe may
    be useful to you.

    http://steven_watanabe.users.sourceforge.net/type_erasure/libs/type_erasure/doc/html/index.html

    Jeff Flinn
    Jeff Flinn, Dec 4, 2012
    #5
  6. Vishal

    Vishal Guest

    > For reference, I repeat the getValue() code here:
    >
    > template<typename T>
    > int getValue(std::list<T> &val) {
    > if ( m_Type == eType::short ) val.push_back(boost::any_cast<short>(m_Value));
    > if ( m_Type == eType::long ) val.push_back(boost::any_cast<long> (m_Value));
    > if ( m_Type == eType::char ) val.push_back(boost::any_cast<char> (m_Value));
    >
    > return 0;
    > }


    Again, you are corrrect. I meant to place a double if statement.

    if ( (m_Type == eType::short) && (m_Type == getType<T>() )


    > Yes, if this is OK regarding your app logic, you can do this. For this
    > you won't need the whole eType system though as boost::any knows its
    > stored type anyway:


    I must be missing something. Boost any may know what type it but the
    documentation doesn't specify a way to get that information. The
    examples show the follow way to determine type. I really don't want
    to throw exceptions for incorrect type cast.

    try
    {
    any_cast<const char *>(operand);
    return true;
    }
    catch(const boost::bad_any_cast &)
    {
    return false;
    }
    Vishal, Dec 4, 2012
    #6
  7. Vishal

    Vishal Guest

    On Dec 4, 5:40 am, Jeff Flinn <> wrote:
    > On 12/3/2012 12:08 PM, Vishal wrote:
    >
    >
    >
    >
    >
    > > On Dec 1, 2:18 am, Paavo Helde <> wrote:
    > >> Vishal <> wrote innews::

    >
    > >>> Hi,

    >
    > >>> I have Class A and according to my requirements the implementation of
    > >>> the class is fixed.  Class A manages the setting/getting of values.
    > >>> The values stored can be of type integer, unsigned integer, character,
    > >>> unsigned character and std::strings.  The available types can grow in
    > >>> the future.  I'm having trouble finding a manageable way of storing
    > >>> values of different types with the ability of retrieving them.  The
    > >>> problem area is class B's getValue method.  It can't be a virtual
    > >>> template method of a non template class.  So, how should I provide a
    > >>> unified way for class A to get a list of all the stored values that
    > >>> match the tag value being passed?

    >
    > >> There is no such thing as a virtual template function. This would require
    > >> recompiling all classes in the class hierarchy and adding vtable slotsto
    > >> all classes whenever a new specialization happens to be called on *any*
    > >> class in the hierarchy. This would mean some serious whole program
    > >> analysis and would not probably work with DLL-s anyway.

    >
    > >> That said, it seems you are wanting some kind of type erasure feature.In
    > >> principle this means to store pointers to dynamically allocated instances
    > >> of different types in your container, and upon retrieval restore the type
    > >> somehow. This sounds similar to boost::any, maybe you can use this.

    >
    > >>> class A
    > >>> {
    > >>>      private:
    > >>>       std::list<B> m_Collection;

    >
    > >> You can't have a list of base class B objects here; when storing derived
    > >> C objects as B they would be sliced. That's why you need to store
    > >> pointers instead. The boost::any class encapsulates this pointer
    > >> mechanism AFAIK and hides such details from you.

    >
    > >> In any case, bear in mind that the template mechanisms are compile-time
    > >> only and cannot dispatch the execution based on information which becomes
    > >> available at run-time only. This probably means that if the run-time type
    > >> of the objects is determined by a "tag", then the tag must appear as a
    > >> template parameter in your interface, in order to avoid run-time switch
    > >> statements.

    >
    > >> hth
    > >> Paavo

    >
    > >> There is no such thing as a virtual template function. This would require
    > >> recompiling all classes in the class hierarchy and adding vtable slotsto
    > >> all classes whenever a new specialization happens to be called on *any*
    > >> class in the hierarchy. This would mean some serious whole program
    > >> analysis and would not probably work with DLL-s anyway.

    >
    > > You are correct.  I discovered the same thing when this didn't work.
    > > It was unfortunate.

    >
    > >> That said, it seems you are wanting some kind of type erasure feature.In
    > >> principle this means to store pointers to dynamically allocated instances
    > >> of different types in your container, and upon retrieval restore the type
    > >> somehow. This sounds similar to boost::any, maybe you can use this.

    >
    > > I'm familiar with boost::any.  I had hoped to use it but couldn't
    > > figure out how to avoid the type cast exception failures if the wrong
    > > type was asked for.  Since, I know that only one type will be correct
    > > I don't want the cost of throwing exceptions to find the correct
    > > type.  I've ended up storing the type that was passed in so I could
    > > figure out which cast to use.  This avoids my issue of using a wrong
    > > cast, but now I need a switch statement.

    >
    > > //Example casting
    > > switch(a)
    > > {
    > > case: eType::float:  cast here
    > > }

    >
    > >> In any case, bear in mind that the template mechanisms are compile-time
    > >> only and cannot dispatch the execution based on information which becomes
    > >> available at run-time only. This probably means that if the run-time type
    > >> of the objects is determined by a "tag", then the tag must appear as a
    > >> template parameter in your interface, in order to avoid run-time switch
    > >> statements.

    >
    > Have you watched the video of Sean Parent's boostcon/C++ Now talk at:
    >
    > http://www.youtube.com/watch?v=_BpMYeUFXv8&feature=plcp
    >
    > The recently accepted boost type erasure library by Steven Watanabe may
    > be useful to you.
    >
    > http://steven_watanabe.users.sourceforge.net/type_erasure/libs/type_e...
    >
    > Jeff Flinn- Hide quoted text -
    >
    > - Show quoted text -


    Thanks. Those were helpful.
    Vishal, Dec 4, 2012
    #7
    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. Xiangliang Meng
    Replies:
    2
    Views:
    404
    Jack Klein
    Jun 21, 2004
  2. IK
    Replies:
    2
    Views:
    592
    hemraj
    Jul 23, 2004
  3. Replies:
    4
    Views:
    363
    mlimber
    Jan 23, 2006
  4. Ashwin
    Replies:
    2
    Views:
    336
    Pierre Barbier de Reuille
    Aug 1, 2006
  5. Peng Yu
    Replies:
    3
    Views:
    754
    Thomas J. Gritzan
    Oct 26, 2008
Loading...

Share This Page