简介: C ++标准区分了依赖于模板参数的符号名称和不符合模板参数的名称,即所谓的两阶段名称查找(参见here)。定义模板时,将尽快解析非依赖名称。另一方面,从属名称仅在模板实例时解析。
示例:
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
中有大约十个typedef / fields / functions,以及几十个派生类,每个类的特定代码少于5行。这意味着大多数代码都包含重复的typedef和using
子句,我知道没有办法完全避免这种情况,但我希望尽量减少这些重复的代码。
感谢任何能让您更容易编写和维护的想法!
答案 0 :(得分:5)
T field;
那应该不是问题; T
是模板参数本身,而不是从属名称。
return n;
这确实是一个问题,因为它是一个从属名称,并且不知道是其成员。最简单的解决方案是
return this->n;
Base<T>::n
和Derived::n
也可以使用,但我不想复制类名。
<强>更新强>
type field;
不幸的是,没有比
更简单地访问依赖类型名称的技巧了typename Base<T>::type field;
答案 1 :(得分:1)
请听我一点
#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;
}
答案 2 :(得分:1)
这不回答这个问题,但是如果你允许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 :: field始终为float,Derived :: f()始终返回5.
如果我们以某种方式欺骗编译器使用Base的每个成员,那么以一种奇怪的方式专门化Base会导致Derived在它应该出错时很难确定。