I am writing a library that provides a class A
and supports evaluations with it (assignment and expressions with infix notation basically). Lets not complicate things unnecessarily and look at the assignment only. The user can do things like:
A a0,a1;
a0=a1;
a1=a0;
At the same time the library should also provide an operation, lets call it fuse
, that takes an arbitrary number of such statements:
fuse(
a0=a1,
a1=a0
);
Same syntax should be used with or without fuse
. In order to make this work I would need a non-standard assignment operator (one that doesn't return a reference to A
but an object that represents the statement) and a separate assign
method:
struct A {
B operator=(const A& a) {
B b(*this,a);
return b;
}
A& assign(const A& a) { // does the actual work }
};
The B
tries to wrap a statement. The assignment operation is triggered in the destruction of B
.
struct B {
B(A& dest,const A& src) : calc(true), dest(dest), src(src) { }
B(B&& b) : calc(b.calc), dest(b.dest), src(b.src) { b.calc=false; }
~B() {
if (calc)
dest.assign(src);
}
bool calc;
A& dest;
const A& src;
};
The bool calc
keeps track of whether this statement need evaluation or not. The fuse
operation comes then with a variadic parameter block:
struct fuse {
template<typename... Bs>
fuse(Bs&&... bs) {
// Recurse and evaluate...
}
};
This setup has a serious flaw: It relies on the compiler calling the move constructor. Because of copy elision rule one cannot do such things.
How to do it without the copy/move constructor?