开发者

Can T in template <typename T> 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 that doesn't 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

In case you're interested, I'm trying to write a general bit of code to handle triangle creation. Each vertex has to have a .pos member, because each vertex has to have a position in space.

However not every vertex type will have a texture coordinate. Not every vertex will have a color. Hence the parameterized types.开发者_JAVA技巧

A similar approach is used in XNA VertexBuffer.SetData<T>.


You cannot specify a type restriction in the template type argument. However, generally, you don't have to.

If you simply do:

template <typename T> addTri( T v1, T v2, T v3 )
{
    Vertex &v1r = v1;
    // ....
}

This will work if the function is instantiated with a derivative of Vertex. It will create an (obscure) error if T & is not convertible to Vertex &.

If you don't even care if the types are convertible to Vertex as long as they have the same members, you can even skip the assignment - C++ template arguments essentially work using duck typing; if you do v1.x, and T contains a member named x, then it will work, whatever type T might actually be.

You can be a bit more sophisticated using boost's type-traits library and a static assertion; with this, you can start defining an assertion to make the error a bit easier to understand:

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;
    // ....
}


A combination of enable_if, is_base_of and is_convertible typetraits should do the job:

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
};

The type traits are available from <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)
{
    ...
}

to disable the generation of addTri if T doesn't inherit from Vertex. But you don't need it to be able to use the pos member.

Update: Actually std::is_base_of will return true if Vertex is an inaccessible base class of T. Use the following implementation of is_base_of instead:

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 solution without the odd :public Vertex. When you instantiate it with a Vertex or with something that just has a pos member, it will be fine. C++ doesn't have to know that every T has a pos member. If you anytime instantiate the template with anything that has no pos member, you will get a compiler error, otherwise it's fine.

What you're looking for is concepts, but they have been dropped from the C++0x standard, I think.


You may be looking at templates wrong. What you describe looks to be handled better by good ole-fashioned inheritance. Instead of passing instances of your object, try passing pointers instead like this:

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 your inheriting objects (casting as the parent class as necessary)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜