1

I have a Builder class which has a number of set methods (with various names and arguments). I need to allow up to 4 of these methods to be called, and no more. I can obviously generate a run-time error if more than 4 set functions are called, but I want to generate a compiler error instead. This would be a programming error, and I would like the opportunity to fix it (decide which 4 calls I want to keep) and not wait until it fails while running (in which case I would have to do something arbitrary like ignore the fifth one). I need a solution which uses standard C++, but not new C++11 features. Below is an example of 5 calls (which should generate a compiler error on the fifth).

Builder builder();  
builder.setA(1);  
builder.setB(1.3);  
builder.setC("sss");  
builder.setD(0);  
builder.setE(3, "aaa");  

1 Answers1

2

You can use something like this:

template <typename T, int N>
struct result {
    T values[N];
};

template <typename T, int I, int N>
class builder_ {
    T*  values;
    friend class builder_<T, I - 1, N>;
    builder_(T* values): values(values) {}
public:
    builder_(result<T, N>& r): values(r.values) {}
    builder_<T, I + 1, N> set(T const& value) {
        *values = value;
        return builder_<T, I + 1, N>(this->values + 1);
    }
};
template <typename T, int N>
class builder_<T, N, N> {
public:
    builder_(T*) {}
};
template <typename T, int N>
builder_<T, 0, N> builder(result<T, N>& r) {
    return builder_<T, 0, N>(r);
}

int main()
{
    result<int, 4> r;
    builder(r)
        .set(1)
        .set(2)
        .set(3)
        .set(4)
        ;
}
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • This solution relies on the programmer always using the chain of set calls. If they call builder.setXXX() 5 times, it will keep setting the first value – user2453360 Dec 01 '15 at 17:53
  • @user2453360: correct. I don't think there is a way to statically count the number of individual calls. – Dietmar Kühl Dec 01 '15 at 17:55
  • @user2453360: a potential approach enforcing the correct number of initializer calls could be the use of the builder to only yield the targeted result in the result, i.e., something along the lines of `result r = builder().set(1).set(2).set(3).set(4);` and arrange for only the specialization for the the target number to be convertible to `result` and provide no mutating operations on `result`. – Dietmar Kühl Dec 01 '15 at 18:01
  • I just realized that builder.setXXX() could be called inside a loop, so the number of calls could not be known at compile time. – user2453360 Dec 01 '15 at 18:49