模板<typename t =“”>中的T可以使用继承吗?</typename>

时间:2011-08-26 21:54:23

标签: c++ templates inheritance

我想做这样的事情:

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

由于这不起作用,这是我的解决方法..

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

背景

如果您感兴趣,我正在尝试编写一些代码来处理三角形创建。 每个顶点都必须有一个.pos成员,因为每个顶点都必须在空间中有一个位置。

然而,并非每个顶点类型都具有纹理坐标。并非每个顶点都有颜色。因此参数化类型。

XNA VertexBuffer.SetData<T>中使用了类似的方法。

5 个答案:

答案 0 :(得分:10)

您无法在模板类型参数中指定类型限制。但是,通常情况下,您没有。

如果您只是这样做:

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

如果函数使用Vertex的导数进行实例化,这将起作用。如果T & 可转换为Vertex &,则会产生(模糊)错误。

如果您甚至不关心类型是否可转换为Vertex,只要它们具有相同的成员,您甚至可以跳过赋值 - C ++模板参数基本上使用duck typing;如果您执行v1.x,并且T包含名为x的成员,那么它将起作用,无论T实际上是什么类型。

使用提升type-traits librarystatic assertion,您可以更复杂一些;有了这个,你可以开始定义一个断言,使错误更容易理解:

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

答案 1 :(得分:4)

enable_ifis_base_ofis_convertible typetraits的组合可以完成这项工作:

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>可以使用类型特征,否则可以<tr1/type_traits>或Boost。

答案 2 :(得分:2)

你可以这样做:

#include <type_traits>

template <typename T> 
void addTri(T v1, T v2, T v3, char (*)[is_base_of<Vertex, T>::value] = 0)
{
    ...
}

如果addTri未从T继承,则禁止生成Vertex。但是您不需要它就可以使用pos成员。

更新:如果std::is_base_ofVertex无法访问的基类,则T实际上会返回true。请改用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;
};

答案 3 :(得分:0)

只使用没有奇数:public Vertex的第一个解决方案。当您使用Vertex或仅具有pos成员的内容实例化它时,它会没问题。 C ++不必知道每个T都有一个pos成员。如果您随时使用没有pos成员的任何内容实例化模板,您将收到编译器错误,否则就没问题。

您正在寻找的是概念,但我认为它们已从C ++ 0x标准中删除。

答案 4 :(得分:-1)

您可能看错了模板。你描述的东西看起来更好地通过良好的烯烃继承来处理。不要传递对象的实例,而是尝试传递指针,如下所示:

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

然后只传递指向继承对象的指针(根据需要转换为父类)