我想做这样的事情:
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>
中使用了类似的方法。
答案 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 library和static 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_if
,is_base_of
和is_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_of
是Vertex
无法访问的基类,则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 ...
}
然后只传递指向继承对象的指针(根据需要转换为父类)