Partial template deduction in constructors

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?

Sto*_*ica 6

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.