Sign in to follow this  
c4c0d3m0n

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

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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)
{
...
}

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.cpp
temp.cpp: In function ‘boost::shared_ptr<T> create() [with T = Child]’:
temp.cpp:34: instantiated from here
temp.cpp:24: error: invalid application of ‘sizeof’ to incomplete type ‘boost::STATIC_ASSERTION_FAILURE<false>’

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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
}



Share this post


Link to post
Share on other sites
1) Don't arbitrarily restrict functionality. How does it break anything to allow create() to create boost::shared_ptr's to other types? I'd actually expect it to be quite useful. This is what templates are for, really. The simplest way to restrict the type is to just forget about it. If some functionality is needed and the type doesn't provide it, the template instantiation will fail. If the functionality isn't needed, what's the problem with allowing it?

2) "What does it mean that the "virtual table" is an unresolved external?"

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this