Mic*_*aël 4 c++ templates constructor c++17
Problem: I'm often in a situation where some types can be deduced from the constructor's arguments, but not all:
template <typename Res, typename Arg>
struct adder {
adder (Arg a1, Arg a2) : a1 {a1}, a2 {a2} {}
void compute () { res = a1 + a2; }
Res result () { return res; }
Arg a1, a2;
Res res;
};
Run Code Online (Sandbox Code Playgroud)
If I'm using int arguments and want to specify unsigned as result type, I would like to write something like:
auto add = adder<unsigned>(42, -51);
Run Code Online (Sandbox Code Playgroud)
…which doesn't work. However, I don't want to explicitly mention int.
Candidate solutions: I can think of two ways to "make it work", first with a maker:
template <typename Res>
struct wrapper {
template <typename Arg>
static auto make_adder (Arg a1, Arg a2) {
return adder<Res, Arg> (a1, a2);
}
};
auto add = wrapper<unsigned>::make_adder (42, -51);
Run Code Online (Sandbox Code Playgroud)
Second by making sure that all types can be deduced in the constructor:
template <typename Res, typename Arg>
struct adder_extra {
adder_extra (Arg a1, Arg a2, Res r) : a1 {a1}, a2 {a2} {}
void compute () { res = a1 + a2; }
Res result () { return res; }
Arg a1, a2;
Res res;
};
auto add = adder_extra (42, -51, (unsigned) 0);
Run Code Online (Sandbox Code Playgroud)
Question: Is there a preferred way? Can this be solved more neatly in another fashion?
An option you did not mention is to do as the standard library does1, and free the maker function:
template <typename Res, typename Arg>
auto make_adder (Arg a1, Arg a2) {
return adder<Res, Arg> (a1, a2);
}
Run Code Online (Sandbox Code Playgroud)
Template argument deduction for functions allows one to specify part of the template arguments. make_adder<unsigned>(42, -51) is perfectly valid, as far back as C++98.
It's a workaround as well, true. But it's a prevalent and idiomatic one.
1 - std::make_unique, std::make_shared, std::make_optional, std::make_any, std::make_tuple, etc.