繁体   English   中英

两阶段查找:可以轻松地混合继承和模板

[英]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有大约十个typedef / fields / functions,以及几十个派生类,每个类的特定代码少于5行。 这意味着大多数代码将由重复的typedef和using子句组成,我知道没有办法完全避免这种情况,但我希望尽量减少这些重复的代码。

感谢任何想法,使这更容易编写和维护!

T field;

那应该不是问题; T是模板参数本身,而不是依赖名称。

return n;

这确实是一个问题,因为它是一个依赖名称,并且不知道是成员。 最简单的解决方案是

return this->n;

Base<T>::nDerived::n也可以,但我不想复制类名。

UPDATE

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 :: field始终为float,Derived :: f()始终返回5。

如果我们以某种方式欺骗编译器使用Base的每个成员,那么以奇怪的方式专门化Base将导致Derived在它应该错误输出时以非常难以确定的方式运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM