First I assume you have some basics that look like this
#include <iostream>
struct vec2 {
double x;
double y;
};
std::ostream& operator<<(std::ostream& stream, vec2 v2) {return stream<<v2.x<<','<<v2.y;}
//real methods
vec2 translate(vec2 in, double a) {return vec2{in.x+a, in.y+a};} //dummy placeholder implementations
vec2 rotate(vec2 in, double a) {return vec2{in.x+1, in.y-1};}
vec2 scale(vec2 in, double a) {return vec2{in.x*a, in.y*a};}
So what you want is a proxy class for operations, where a proxy object is constructed with the function and the "other parameters". (I made the function a template parameter, which prevents the use of function pointers, and helps the optimizer to inline, making this nearly zero overhead.)
#include <type_traits>
//operation proxy class
template<class rhst, //type of the only parameter
vec2(*f)(vec2,rhst)> //the function to call
class vec2_op1 {
std::decay_t<rhst> rhs; //store the parameter until the call
public:
vec2_op1(rhst rhs_) : rhs(std::forward<rhst>(rhs_)) {}
vec2 operator()(vec2 lhs) {return f(lhs, std::forward<rhst>(rhs));}
};
//proxy methods
vec2_op1<double,translate> translate(double a) {return {a};}
vec2_op1<double,rotate> rotate(double a) {return {a};}
vec2_op1<double,scale> scale(double a) {return {a};}
And then you simply make that chainable
//lhs is a vec2, rhs is a vec2_operation to use
template<class rhst, vec2(*f)(vec2,rhst)>
vec2& operator|(vec2& lhs, vec2_op1<rhst, f>&& op) {return lhs=op(lhs);}
Usage is simple:
int main() {
vec2 v2{3,5};
v2 | translate(2.5) | rotate(30) | translate(3) | scale(2);
std::cout << v2;
}
http://coliru.stacked-crooked.com/a/9b58992b36ff12d3
Note: No allocations, no pointers, no copies or moves. This should generate the same code as if you just did v2.translate(2.5); v2.rotate(30); v2.scale(10);
directly.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…