是否可以完全模拟虚拟运算符++(int)?

时间:2016-12-02 13:15:44

标签: c++ inheritance operator-overloading crtp

由于返回类型问题,我们无法直接生成operator++(int) virtual。通常的建议是应用奇怪命名的Curiously Recurring Template Pattern,我最好的谦虚理解实施如下:

// abstract numeric type
template <typename T>
class A {
public:
    virtual T& operator++() = 0;
    virtual T get() const = 0;
    virtual string toString() const = 0;
    virtual T operator++(int) {
        T old(this->get());
        ++*this; // calls operator++() from derived class
        return old;
    }
    friend ostream& operator<<(ostream& os, const A& a) {
        return os << a.toString();
    }
    virtual ~A() = 0;
};

// signed numeric type
class S : public A<S> {
public:
    S(long l) : m_l(l) {}
    virtual S get() const { return m_l; }
    virtual string toString() const { return to_string(m_l); }
    virtual S& operator++() { // no wrapping, caps at LONG_MAX
        if (m_l < LONG_MAX)
            ++m_l;
        return *this;
    }
private:
    long m_l;
};

// unsigned numeric type
class U : public A<U> {
public:
    U(unsigned long ul) : m_ul(ul) {}
    virtual U get() const { return m_ul; }
    virtual string toString() const { return to_string(m_ul); }
    virtual U& operator++() { // no wrapping, caps at ULONG_MAX
        if (m_ul < ULONG_MAX)
            ++m_ul;
        return *this;
    }
private:
    unsigned long m_ul;
};

很多代码重复,但至少它允许运行以下结构,这绝对是一个开始:

template <typename T>
void pinc(A<T>& a) {
    cout << a++ << ' ' << a << endl;
}

int main() {
    S s(LONG_MAX);
    pinc(s);

    U u(LONG_MAX);
    pinc(u);

    return 0;
}

可悲的是,它对vector<A*>之类的内容没有帮助:SU没有共同的祖先。如果我从另一个基类派生A,我还必须将模板化部分移到那里并解决问题 - 哈! - 递归。

那么,有什么建议吗?

编者注:在吸取了教训后,我这次保存了原文。 :)

1 个答案:

答案 0 :(得分:0)

我不认为在C ++类型系统中这是可能的,这就是为什么:

请考虑以下示例:假设我们以某种方式实现此目标并且具有指向A* aU的基类的S指针。那么var = (*a)++;的类型是什么?它可以是US,具体取决于a指向的内容。但编译器需要在编译期间知道返回类型 ,因为operator ++(int)返回SU by-value。

我看到以下解决此问题的方法,但他们都需要更改层次结构中operator++(int)的返回类型以使其协变(请参阅C++ virtual function return type):

  1. 返回指向层次结构中(基类)的指针

  2. 如果你的类型是整数类型(比如operator ++返回charintlong用于不同的类)那么你可以让它们全部返回封闭类型:{{1 }}

  3. 不是返回对象的直接值(long intU),而是返回某种能够保存这些类型的结构。 (有关可能的通用方法,请参阅http://www.boost.org/doc/libs/1_61_0/doc/html/any.html