We cannot make operator++(int)
virtual
directly because of the return type problem. The usual advice is to apply the curiously named Curiously Recurring Template Pattern
, which I implemented to the best of my modest understanding as follows:
// 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;
};
Lots of code duplication, but at least it allows for constructs like the following to run, which is definitely a start:
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;
}
Sadly, it does not help with things like vector<A*>
: S
and U
have no common ancestor. If I derive A
from another base class, I also have to move the templated part there and the problem - ha! - goes recursive.
So, any suggestions?
Note to editors: Having learned my lesson, I saved the original this time. :)
I do not think this is possible within C++ type system, here is why:
Consider the following example: Let say we somehow achieve this and have A* a
pointer to the base class from which U
and S
was derived. Then what will be the type of the var = (*a)++;
? It could be either U
or S
depending on what a
is pointing to. But compiler need to know return type during compilation because operator++(int) return S
and U
by-value.
I see the following ways to work around this problem but they all need to change the return types of operator++(int)
in hierarchy to make them covariant (see C++ virtual function return type ):
Return pointer to a (base) class within your hierarchy
If your types is integer types (like operator++ return char
, int
, long
for different classes) then you can make them all return enclosing type: long int
Instead of returning direct values of your objects ( U
or S
) return some kind of struct that is capable of holding any of these types. (see http://www.boost.org/doc/libs/1_61_0/doc/html/any.html for possible generic way to do this)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.