typedeffing模板化基类是简化代码的一个好习惯吗?

时间:2014-01-30 15:58:39

标签: c++ templates

在使用许多模板化类并从中衍生出来时,我最近发现了“发明”这个简单的结构。我不确定这是不是常见的做法,还是我在脖子上系绳子。

template <typename T> class Base {};

template <typename T> class Derived : public Base<T>{
  typedef Base<T> Base;
};

如果Base类对某些类型有自己的typedef,我发现它特别有用。 E.g:

template <typename T> class Base {
  typedef T Scalar;
  typedef Matrix<Scalar> Matrix;
};

然后很容易将“导入”类型导入Derived。它可以节省重新键入模板签名的麻烦。 E.g:

template <typename T> class Derived : public Base<T>{
  typename Base<T>::Matrix yuck_yuck(); //that's what I am trying to simplify
  typedef typename Base<T> Base;
  typedef typename Base::Matrix Matrix;
  Matrix much_fun(); //looks way better
};

另外一个很大的优点是,当您想要向Base类添加另一个模板参数时。您无需更改大量功能,只需更新typedef即可。 much_fun如果Base更改为Base<T,U>yuck_yuck将需要更新签名(不确定模板参数是否正式包含在签名中,那么Base会有问题,所以请原谅我,如果我在这里发出正式错误,但我认为是。)

这是一个很好的练习还是我在我的重要部位旁边玩枪?看起来它使代码更具可读性并简化了它,但也许我错过了可能适得其反的事情。

EDIT2:我得到了一个有效的例子。 namespace Fun { template <typename T> class Base { public: typedef T Scalar; }; } template <typename T> class Derived : public Fun::Base<T>{ public: typedef typename Fun::Base<T> Base; typedef typename Base::Scalar Scalar; typename Fun::Base<T>::Scalar yuck_yuck(); Scalar much_fun(); }; #include <iostream> using namespace std; int main() { Derived<double> d; return 0; } 类必须在其命名空间内,否则将在范围内与相同的名称发生冲突,如评论者指出的那样。以下是体现我真实问题的最小例子。

typenames

有很多东西,代码变得非常臃肿Base和模板参数。但是,我已经在编写示例时遇到了麻烦,因为没有将{{1}}放在自己的命名空间中。我想知道是否有任何其他警告,实际上是这个想法的杀手。

2 个答案:

答案 0 :(得分:5)

由于C ++ 11 3.3.7 / 1

的规则2,我认为这是不正确的
  

在类S中使用的名称N应在其上下文中引用相同的声明,并在完成的S范围内重新评估。

意味着您不能使用名称Base来引用类范围内的模板和typedef。当然,我的编译器不会接受它:

error: declaration of ‘typedef struct Base<T> Derived<T>::Base’ [-fpermissive]
error: changes meaning of ‘Base’ from ‘struct Base<T>’ [-fpermissive]

(注意:这是指最初发布的简化示例,并未涵盖基类名称在不同范围内的更新问题。)

答案 1 :(得分:1)

如果typedef未公开或受到保护,我实际上认为这是一种有用(且很好)的做法:

// No template, not Base, to avoid that discussion
class Derive : public SomeBaseClass 
{
   private:
   typedef SomeBaseClass Base;

   public:
   typedef Base::T T;

   T f();
}; 

class MoreDerived : public Derived
{
   // Base is not accessible
};