1

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?

ritter
  • 7,447
  • 7
  • 51
  • 84
  • Couldn't `fuse` be a variadic template function? – juanchopanza Aug 03 '12 at 11:56
  • Yes, actually it is. It's shown in the code above. But somehow you must make a type out of the statement, so that it can go into `fuse` variadic parameter block – ritter Aug 03 '12 at 11:58
  • 2
    You don't need to call `std::move` when returning a local variable, see [this](http://stackoverflow.com/q/11492948/500104), [this](http://stackoverflow.com/q/9532608/500104) and [this](http://stackoverflow.com/q/11088023/500104) question. :) – Xeo Aug 03 '12 at 12:13
  • 3
    Also, move elision really is a non-issue here. Elision means that you never created that local variable but instead constructed directly into the destination variable. There will be no "old" `B` that now needs to know that it shouldn't do calculation. And on "non-standard" assignment operators, EDSL (embedded domain-specific language, like Boost.Spirit) do this all the time. – Xeo Aug 03 '12 at 12:15
  • @Xeo, right! Regards `calc`: I wanted to also catch the case where the compiler does not elide the call to the move/copy constructor. – ritter Aug 03 '12 at 12:19
  • 2
    In that case, there is still no problem. The compiler will only ever elide copies/movies in pairs with the destruction of the "old"/temporary object. If it elides the move, it elides the destruction. If it doesn't, both move and destruction will occur and you're fine. – Xeo Aug 03 '12 at 12:20
  • Makes sense. Could be okay then. – ritter Aug 03 '12 at 12:24
  • I do not understand *"Same syntax should be used with or without fuse"*. What do you mean by this. Can you elaborate both? With an specific example? Remember: The C++-Spec says you must not rely on the order of evaluation for the arguments of a function call. Thus `fuse(a0=a1, a1=a0);` is implementation-defined, as far as I can see. Or do you use `a0` and `a1` only as a stand-in for "anything" here? – towi Jan 17 '13 at 16:14
  • The `B`s are proxy objects that represent expression, but their construction does not (yet) trigger evaluation. Only references and operations form the structure of `B`. I think the construction order of `B`s does not matter. The "correct" order is respected when it comes to recursive expansion of the variadic parameter block. The "same syntax" is meant to just wrap a `fuse(...)` around a sequence of statements replacing `;` with `,`. Otherwise I wouldn't know how to pass the sequence to a function. – ritter Jan 18 '13 at 15:15

0 Answers0