Consider the following builder-like class, which ultimately allows me to construct an object with both certain (runtime) values for member variables, as well as embedding some behavior which is carried by several (compile-time) types.
The same build allows one to update member variables (the usual builder pattern), as well as change template type parameters associated with the type-carried state of the builder (only shown with a couple of template type parameters and members, but in practice, there would be more):
template <typename T1 = DefaultT1, typename T2 = DefaultT2>
class Builder {
int param1, param2;
Builder(int param1, int param2) : param1{param1}, param2{param2} {}
public:
Builder() : Builder(default1, default2) {}
// methods to change param1 and param2 not shown
/* return a new Builder with T1 changed to the given T1_NEW */
template <typename T1_NEW>
Builder<T1_NEW, T2 > withT1() { return {param1, param2}; }
template <typename T2_NEW>
Builder<T1 , T2_NEW> withT2() { return {param1, param2}; }
Foo make() {
// uses T1 and T2 to populate members of foo
return Foo{ typename T1::member, typename T2::another };
}
};
Note the withT1<>
and withT2<>
methods which allow you to return a new builder with a different type for T1
or T2
respectively. The bodies for these methods are identical: return {param1, param2};
, and in practice much more complicated than shown here (e.g., if there are many parameters).
I'd like to factor the body out into some method which does the construction, like:
template <typename T1_, typename T2_>
Builder<T1_, T2_> copy() { return {param1, param2}; }
and then each withT*
method could just call copy.
However, it isn't clear to me how to avoid including the fully qualified type of Builder
in the call:
template <typename T1_NEW>
Builder<T1_NEW, T2 > withT1() { return copy<T1_NEW, T2>(); }
Here the cure is worse than the original poison since I need to qualify each copy call with <T1_NEW, T2>
(and this is different for each withT*
method). Is there some way I can refer to the return type or another type of deduction which I can use to call copy()
in the same way in each function?
I'm writing in C++11, but discussion of how a C++11 solution could be improved in later standards is also welcome.