Can T in <typename T> pattern use inheritance?
I want to do something like this:
template <typename T:public Vertex> addTri( T v1, T v2, T v3 ) { // Take v1.pos, v2.pos, v3.pos and create a geometric repn.. Triangle tri( v1.pos, v2.pos, v3.pos ) ; // all vertices will // have to have a .pos member. // Create the vertex buffer.. VertexBuffer<T> vb ... } Since this does not work, this is my workaround.
template <typename T> addTri( T v1, T v2, T v3 ) { Vertex* p1 = (Vertex*)&v1 ; // This is a very "shut up C++, I know what I'm doing" type cast. // I'd like for C++ to know that all vertex types (T in this case) // __will__ have a Vector member .pos. Triangle tri( p1->pos, p2->pos, p3->pos ) ; // Create the vertex buffer.. VertexBuffer<T> vb ... } Background
If you're interested, I'm trying to write a common bit of code to handle creating a triangle. Each vertex must have a .pos member, because each vertex must have a position in space.
However, not every type of vertex will have a texture coordinate. Not every vertex will have color. Therefore, parameterized types.
A similar approach is used in XNA VertexBuffer.SetData<T> .
You cannot specify a type constraint in a template type argument. However, as a rule, you do not need to.
If you just do:
template <typename T> addTri( T v1, T v2, T v3 ) { Vertex &v1r = v1; // .... } This will work if the function is instantiated by Vertex. It will create a (obscure) error if T & does not convert to Vertex & .
If you don't care if the types are converted to Vertex , if they have the same members, you can even skip the assignment - the C ++ template arguments essentially work using duck print ; if you are running v1.x and T contains a member named x , then it will work no matter what type T can be.
You can be a little more complex using the boost type type library and static statement ; with this, you can start defining the statement to make the error more understandable:
template <typename T> addTri( T v1, T v2, T v3 ) { BOOST_STATIC_ASSERT_MSG(boost::is_convertible<T&, Vertex&>::value, "Template argument must be a subclass of Vertex"); Vertex &v1r = v1; // .... } The combination of enable_if , is_base_of and is_convertible typetraits should complete the following task:
template <typename T> struct Foo : public std::enable_if<std::is_base_of<YourBase, T>::value && std::is_convertible<T&, A&>::value, T>::type { // consider "using YourBase::foo;" directives here }; Type traits are available in <type_traits> in modern compilers, or <tr1/type_traits> or Boost otherwise.
You can do:
#include <type_traits> template <typename T> void addTri(T v1, T v2, T v3, char (*)[is_base_of<Vertex, T>::value] = 0) { ... } disable addTri generation if T not inherited from Vertex . But you do not need it to use the pos member.
Update: Actually std::is_base_of will return true if Vertex is an unavailable base class of T Instead, use the following implementation of is_base_of :
template <typename B, typename D> struct is_base_of { static const bool value = std::is_convertible<D*, B*>::value && std::is_class<B>::value; }; Just use your first oddless solution :public Vertex . When you instantiate using Vertex or with something that only has the pos member, everything will be fine. C ++ should not know that every T has a pos member. If you ever create an instance of a template with anything that does not have a pos member, you will get a compiler error, otherwise it will be fine.
What you are looking for are concepts, but they, in my opinion, have been excluded from the C ++ 0x standard.
You may not look at the templates correctly. What you describe looks better than good oleo-shaped inheritance. Instead of passing instances of your object, try specifying pointers instead:
addTri( Vertex *v1, Vertex *v2, Vertex *v3 ) { // Take v1.pos, v2.pos, v3.pos and create a geometric repn.. Triangle tri( v1->pos, v2->pos, v3->pos ) ; // all vertices will // have to have a .pos member. // Create the vertex buffer.. VertexBuffer<T> vb ... } Then just pass pointers to inheriting objects (if necessary, as a parent class)