将模板化函数限制为基类和派生类型?

时间:2011-11-02 21:59:24

标签: c++ templates

我有一个像这样的模板基类:

template<typename T, std::size_t Size>
class VectorT
{
public:
    typedef T data_type;
}

和一些专门的派生类:

template<typename T>
class Vector2d : public VectorT<T, 2U>
{ // some specialised functions }

template<typename T>
class Vector3d : public VectorT<T, 3U>
{  // some other specialised functions }

这些工作正常。但是,我为运营商提供了一些独立的功能。例如:

template<typename T, size_t Size>
VectorT<T, Size> operator*(T lhs, const VectorT<T, Size>& rhs)
{
    ... 
}

不幸的是,这些对我的派生类不起作用,因为它们返回VectorT<T, Size>而不是Vector2d<T>

所以我尝试了

template<V>
V operator*(typename V::data_type lhs, const V& rhs)
{
    ... 
}

并且这样可以正常工作,但是它可能会导致含糊不清,因为它对data_type成员的其他任何东西都很糟糕。

我怎样才能解决这个问题:如何编写仅适用于我的矢量库或任何衍生物的类型安全函数?

我试图绕过必须重新声明并重新定义子类的运算符。

2 个答案:

答案 0 :(得分:7)

您可以添加另一个基类,一个独立于模板参数的基类,并使用SFINAE禁用对从此基类派生的类型以外的类型的调用:

struct VectorBase {};

template< typename T, std::size_t Size >
class VectorT : public VectorBase { ... }

template< typename V >
typename boost::enable_if< boost::is_base_of< VectorBase, V >, V >::type
operator*( V lhs, V const& rhs ){ ... }

请注意,is_base_of< X, X >始终为true,因此此函数将比另外一种类型工作,即基类VectorBase

如果您使用的是实现TR1的编译器,则可以在使用的两个地方替换boost:: std::

答案 1 :(得分:1)

你处于一种不寻常的境地,没有“好”的方式。你可以:

  1. 在运行时检查类型(或编译时,boost可能会这样做)
  2. 取一个VectorT<>&并使用它而不是在函数内创建一个新的VectorT并返回它。这样您也可以通过引用获取VectorT的子类。这会让你不得不使用函数而不是运算符。
  3. 做K-ballo所说的。