两阶段查找:是否可以轻松地混合继承和模板
Two-phase lookup: is it possible to easily mix inheritence and templates
简介:C++标准区分依赖于模板参数的符号名称和不依赖于模板的名称,这称为两阶段名称查找(请参阅此处(。定义模板时,会尽快解析非从属名称。另一方面,从属名称仅在模板实例化时解析。
示例:
template<class T> struct Base {
typedef T type;
static const int n = 3;
virtual int f() = 0;
int f(int x) { return x * 2; }
};
// doesn't compile!
template<class T> struct Derived : Base<T> {
type field; // The compiler doesn't know Base<T>::type yet!
int f() { return n; } // the compiler doesn't know n yet, and f(int) is maksed!
};
目前,我所做的是这样定义Derived
:
template<class T> struct Derived : Base<T> {
typedef Base<T> Parent;
typedef typename Parent::type type; // correct but
using Parent::n; // boring, long
using Parent::f; // and harder to maintain
type field;
int f() { return n; }
};
对我来说,面向对象编程的主要目标之一是减少代码重复;这种失败的目的。。。
问题:有没有其他方法可以通过使用我不知道的语法或聪明的技巧来定义Derived
?我喜欢这样的东西:
template<class T> struct Derived : Base<T> {
using Base<T>::*; // I promise I won't do strange specializations of Base<T>
type field;
int f() { return n; }
};
编辑澄清:也许我不够具体。假设您在Base
中有大约十个typedefs/fields/functions,以及几十个派生类,每个派生类的特定代码不到5行。这意味着大多数代码将由重复的typedefs和using
子句组成,我知道没有办法完全避免这种情况,但我希望尽量减少这种重复的代码。
感谢您的任何想法,使其更易于编写和维护!
T field;
这不应该是个问题;T
是模板参数本身,而不是依赖名称。
return n;
这确实是一个问题,因为它是一个从属名称,不知道是成员。最简单的解决方案是
return this->n;
Base<T>::n
和Derived::n
也可以,但我不希望重复类名。
更新
type field;
不幸的是,没有比更简单地访问依赖类型名的技巧了
typename Base<T>::type field;
听我说一点
#include <string>
#include <iostream>
template<class T> struct Base {
typedef T type;
static const int n = 3;
virtual int f() = 0;
int f(int x) { return x * 2; }
};
// does compile
template< class T, template<typename> class Base = Base >
struct Derived : Base<T>
{
typename Base<T>::type field;
int f()
{
field = 200;
return n;
}
int f(int x)
{
return Base<T>::f(x);
}
};
int main()
{
Derived<int> bss;
std::cout << bss.f() << std::endl;
std::cout << bss.f(50) << std::endl;
std::cout << bss.field << std::endl;
return 0;
}
这并不能回答问题,但如果你确实允许对Base进行专门化(你真的必须这样做(,那么行为可能会变得非常奇怪。
比如考虑这个例子。。。
template<class T> struct Base {
typedef T type;
static const int n = 3;
virtual int f() = 0;
int f(int x) { return x * 2; }
};
typedef float type;
static const int n = 5;
template<class T> struct Derived : Base<T> {
type field;
int f() { return n; }
};
这可能不是直观的,但至少代码是可预测的。Derived::字段始终为浮点值,Derived:::f((始终返回5。
如果我们以某种方式欺骗编译器使用Base的每个成员,那么以一种奇怪的方式专门化Base将导致Derived在很难确定何时出错时的行为。
相关文章:
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 在混合代码库中将C转换为C++时出现许多包含错误
- 为什么这个混合继承程序给出错误的输出?
- 有没有一种干净(更)的方法将 CRTP 与可变参数继承混合在一起?
- 将从基类继承的构造函数与自定义构造函数混合使用
- 好奇的循环继承与C++中的混合
- 混合模板/非模板继承分类和成员继承
- MinGW 4.7.0 到 4.7.2 错误:使用混合虚拟和非虚拟多重继承时成员函数中的"this"指针无效
- 虚拟和非虚拟继承的混合
- 带有混合继承修饰符(protected/private/public)的钻石继承
- 将抽象类继承与实例化模板混合
- 类成员的继承,与模板混合
- 可变模板混合继承的可见性规则
- 两阶段查找:是否可以轻松地混合继承和模板