As noted by others, the calls to myFunction2()
are unordered relative to each other. So it isn't the same.
As an attempt to make them ordered, we might do something like this:
template<typename T>
struct continuation {
T&& t;
continuation(T&& t_):t(std::forward<T>(t_)) {}
continuation( continuation&& ) = delete;
continuation( continuation const& ) = delete;
continuation() = delete;
void operator=(continuation const&) = delete;
void operator=(continuation &&) = delete;
template<typename Lambda>
continuation<T> then( Lambda&& closure ) && {
std::forward<Lambda>(closure)( std::forward<T>(t) );
return { std::forward<T>(t) }; // two forwards! Dangerous
}
};
struct myClass {
continuation<myClass&> myFunction1(int) &{ return {*this}; }
continuation<myClass> myFunction1(int) &&{ return {*this}; }
int myFunction2() const { return 7; }
};
int main() {
myClass c;
c.myFunction1( c.myFunction2() ).then( [](auto&& c) { c.myFunction1( c.myFunction2() ); } );
}
would be an example of code that would let you chain your use of the class instance on one line with the same order of operations (in C++1y).
However, continuation style then
calls are traditionally used for future return values rather than ordered evaluation of chain calls to this
.
It also gets really annoying with all of the nested brackets. One way to approach that problem is to use a named operator *then*
, which requires a bit more boilerplate, but gives you:
int main() {
myClass c;
c.myFunction1( c.myFunction2() )
*then* [](auto&& c) { c.myFunction1( c.myFunction2() ); }
*then* [](auto&& c) { c.myFunction1( c.myFunction2() ); };
}
which looks sort of pretty.
All of this is basically a way to avoid creating a simple alias.
myClass get_my_class() { return {} };
int main() {
auto&& c = get_my_class();
c.myFunction1(c.myFunction2());
c.myFunction1(c.myFunction2());
c.myFunction1(c.myFunction2());
}
both does not require any of the gymnastics above, and is at least as efficient. If you have a complex name for some object and you want to avoid saying it again, using a reference works in all but some corner cases.
The corner case in particular is a function that returns a reference to an object whose lifetime ends at the end of the current line. This is generally bad practice: with easy-to-move objects at least, you should instead return a temporary.
However, a situation where this is unavoidable may occur. Rather than method chaining or continuation or whatever, consider creating a simple lambda or function that chains the operations, and call it on the single line that the object exists on. Alternatively, break the line down and store the lifetime of the object via reference extension of its original incarnation.