user1095108
user1095108

Reputation: 14603

How to avoid having to write boilerplate accessor code

I find, when coding C++ code, that I spend a lot of time writing accessor boiler plate code, such as:

class A
{
  int x;

public:
  auto x();
  void set_x(decltype(x));
};

The whole idea of implementing accessors revolves around being able to intercept read and write accesses to them. I stumbled on this library (I'm not the author). It really makes me wonder, if, to avoid having to write boilerplate code, one could/should just write something like:

class A
{
public:
  property<int> x;

  A() {
    x.setter([this](int){ /* setter code */ });
  }
};

My question is: What techniques are available to avoid having to write a lot of boilerplate code for getters and setters?

Upvotes: 3

Views: 823

Answers (2)

TobiMcNamobi
TobiMcNamobi

Reputation: 4813

There is some discussion here and there about whether getters and setters are evil in general.

So, my strategy for avoiding boilerplate code: Try to avoid getters and setters. When in need of some pure data class I declare the (few) fields public. But in these cases I try to avoid giving them any other logic, I try to keep these classes as little as possible.

Also, read about tell-don't-ask, e.g. from Martin Fowler.

Upvotes: 1

Anedar
Anedar

Reputation: 4275

I guess you are looking for something like this:

template <typename T>
class Property{
    private:

    T val;

    std::function<void(T& v,const T& newV)> setFN = nullptr;

    public:

    void setter(decltype(setFN) newSetter){
        setFN = newSetter;
    }

    void set(const T& newVal){
        if(!setFN)
            val = newVal;
        else
            setFN(val,newVal);
    }

    T get(){
        return val;
    }
};

So basically a template class, that is able to store a setter-function. If one is stored, it is called, if not, just a operator= is used (which needs to be defined by T, of course).

Usage:

int main() {

    Property<int> x;

    x.set(5);
    std::cout << x.get() << std::endl;

    x.setter([](int& v, const int& newV){std::cout << "Setter called\n"; v=newV;});

    x.set(2);
    std::cout << x.get() << std::endl;

    return 0;
}

Output:

5
Setter called
2

Try it online

It shoud be easy to implement the getter function in a similar way.

Upvotes: 0

Related Questions