Search code examples
c++functionvariablesc++11bind

Define or bind member function to 'variable like' keyword. Execution without parentheses


Is there a way to bind member function to something like member variable?

Let's say i have simple vector struct:

struct Vec3 {
    int x, y, z;

    Vec2 xy() const { return Vec2(x, y); }
    Vec2 xz() const { return Vec2(x, z); }
    Vec2 yz() const { return Vec2(y, z); }
}

Now i can use it like:

Vec3 t = { 5, 3, 2 };
Vec2 s = t.xy() + t.yz();

But is there a way i could use it like:

Vec3 t = { 5, 3, 2 };
Vec2 s = t.xy; // this here ? execute function without '()'.

Solution

  • While C++ does not offer properties by default, you can implement them pretty easily by yourself. Here is a simplistic approach:

    #include <functional>
    
    template<typename T>
    struct property
    {
    public:
      typedef std::function<T()> getter;
      typedef std::function<void(T)> setter;
    
    public:
      property(getter get, setter set)
      : get_(get)
      , set_(set)
      { }
    
      operator T() const { return get_(); }
      property& operator=(T x) { set_(x); return *this; }
    
    private:
      getter get_;
      setter set_;
    };
    

    We can now rewrite your Vec3 class using these 'properties':

    class Vec3
    {
    public:
      Vec3(int vx, int vy, int vz)
      : x(std::bind(&Vec3::get_x, this), std::bind(&Vec3::set_x, this, std::placeholders::_1))
      , y(std::bind(&Vec3::get_y, this), std::bind(&Vec3::set_y, this, std::placeholders::_1))
      , z(std::bind(&Vec3::get_z, this), std::bind(&Vec3::set_z, this, std::placeholders::_1))
      , xy(std::bind(&Vec3::get_xy, this), std::bind(&Vec3::set_xy, this, std::placeholders::_1))
      , xz(std::bind(&Vec3::get_xz, this), std::bind(&Vec3::set_xz, this, std::placeholders::_1))
      , yz(std::bind(&Vec3::get_yz, this), std::bind(&Vec3::set_yz, this, std::placeholders::_1))
      , x_(vx)
      , y_(vy)
      , z_(vz)
      { }
    
      property<int> x;
      property<int> y;
      property<int> z;
    
      property<Vec2> xy;
      property<Vec2> xz;
      property<Vec2> yz;
    
    protected:
      int get_x() { return x_; }
      void set_x(int x) { x_ = x; }
    
      int get_y() { return y_; }
      void set_y(int y) { y_ = y; }
    
      int get_z() { return z_; }
      void set_z(int z) { z_ = z; }
    
      Vec2 get_xy() { return { x_, y_ }; }
      void set_xy(Vec2 xy) { x_ = xy.x; y_ = xy.y; }
    
      Vec2 get_xz() { return { x_, z_ }; }
      void set_xz(Vec2 xz) { x_ = xz.x; z_ = xz.y; }
    
      Vec2 get_yz() { return { y_, z_ }; }
      void set_yz(Vec2 yz) { y_ = yz.x; z_ = yz.y; }
    
    private:
      int x_, y_, z_;
    };
    

    Which can be used like this:

    std::ostream& operator<<(std::ostream& out, const Vec2& v2)
    {
      out << '[' << v2.x << ", " << v2.y << ']';
      return out;
    }
    
    std::ostream& operator<<(std::ostream& out, const Vec3& v3)
    {
      out << '[' << v3.x << ", " << v3.y << ", " << v3.z << ']';
      return out;
    }
    
    int main(int argc, char** argv)
    {
      Vec3 v3 { 2, 0, 1 };
      std::cout << v3 << std::endl;
      v3.y = 3;
      std::cout << v3.xy << std::endl;
      std::cout << v3.xz << std::endl;
      std::cout << v3.yz << std::endl;
    
      return 0;
    }
    

    As you can see, what you are asking is possible, it just requires a lot of code.

    See the live example on ideone