在使用许多模板化类并从中衍生出来时,我最近发现了“发明”这个简单的结构。我不确定这是不是常见的做法,还是我在脖子上系绳子。
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}}放在自己的命名空间中。我想知道是否有任何其他警告,实际上是这个想法的杀手。
答案 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
};