Templates [C++] - Why doesn't this work?

Started by
11 comments, last by Zahlman 15 years, 6 months ago
#include <boost/shared_ptr.hpp>

class Parent
{
  public:
    virtual void foo();
    int bar;
};

class Child : public Parent
{
  public:
    void foo() { bar++; };
    int bar;
};



template <Parent T>
boost::shared_ptr<T>
create()
{
    boost::shared_ptr<T> pointer( new T );
    return pointer;
}



int main()
{
    boost::shared_ptr<Parent> pointer = create<Child>();
    return 0;
}

temp.cpp:19: error: ‘class Parent’ is not a valid type for a template constant parameter
I always thought I could create a template of whatever I want, not just a class.. Could someone please explain why this is not allowed? What I basically want is a template that only allows classes inherited from Parent. How would I go on about this?
Advertisement
Ok, there are two problems. The first problem is that non-type template parameters need to be either integral constants or a pointer or reference to an entity with external linkage, so you need to have a Parent * or Parent &. The second problem is that you aren't using it as a non-type template parameter, since you're trying to use Child as the template parameter. Basically, the way you're using it you should replace Parent with class or typename.
Quote:Original post by c4c0d3m0n
*** Source Snippet Removed ***

temp.cpp:19: error: ‘class Parent’ is not a valid type for a template constant parameter



I always thought I could create a template of whatever I want, not just a class.. Could someone please explain why this is not allowed?

What I basically want is a template that only allows classes inherited from Parent. How would I go on about this?


You need to change your code to:

template <class T>boost::shared_ptr<T> create(){   boost::shared_ptr<T> pointer(new T);   return pointer;}int main){...}
Author Freeworld3Dhttp://www.freeworld3d.org
Thanks for the quick replies!


@SiCrane:
I am not sure what you mean by "pointer or reference to an entity with external linkage" I do see now why the code wouldn't work anyway; Child is not of type Parent (the second issue you addressed).


@soconne:
The problem with that code is that it would also allow classes that are not inherited from Parent. How can I make it so only classes inherited from Parent are allowed as template parameter?
The simplest way to restrict it to child classes of your Parent class would be to add a BOOST_STATIC_ASSERT() that Parent is a base of the template type. boost::type_traits' is_base_of would probably be the most straightforward way to ensure that.
Hmm.. I seem to be very terible at finding good boost documentation through google, but I found an example on a mailing list. Still, I can't quite get it to work...


template <class T>boost::shared_ptr<T>create(){    BOOST_STATIC_ASSERT(( boost::is_base_of<T, Parent>::value ));    boost::shared_ptr<T> pointer( new T );    return pointer;}


rob@rob-laptop:~/Desktop$ g++ temp.cpptemp.cpp: In function ‘boost::shared_ptr<T> create() [with T = Child]’:temp.cpp:34:   instantiated from heretemp.cpp:24: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’ 
I think you want <Parent, T> not <T, Parent>
In that case I get funky errors about the vtables in Parent ... oO

rob@rob-laptop:~/Desktop$ g++ temp.cpp/tmp/ccWNjx4L.o: In function `Parent::Parent()':temp.cpp:(.text._ZN6ParentC2Ev[Parent::Parent()]+0x4): undefined reference to `vtable for Parent'/tmp/ccWNjx4L.o:(.rodata._ZTI5Child[typeinfo for Child]+0x8): undefined reference to `typeinfo for Parent'collect2: ld returned 1 exit status



edit:
If I remove all the contents of the classes, it seems to work. Maybe something wasnt kosher with the using no::brain inheritance up there
That probably has something to do with the fact you never provide a definition for Parent::foo().
Quote:Original post by c4c0d3m0n
@soconne:
The problem with that code is that it would also allow classes that are not inherited from Parent. How can I make it so only classes inherited from Parent are allowed as template parameter?


Oooohh, sorry, I should have read your post more carefully. One way to solve it is to use the dynamic_cast function.

class Parent { };class Child : public Parent { };template <typename P, typename T>boost::shared_ptr<T> create(){    T* t = new T();    if (dynamic_cast<P*>(t) != 0)        return boost::shared_ptr(t);    else        // throw error or return 0}
Author Freeworld3Dhttp://www.freeworld3d.org

This topic is closed to new replies.

Advertisement