Search code examples
c++visual-c++template-argument-deduction

template parameter deduction from templated non-type template argument


I have the following typedef:

template<typename G, typename T, typename R>
using my_func_type = typename R(T::*)(G, int) const;

It is a member function I use a lot, so I'm playing around with making different wrappers for. The premise is that I want an object that implements these functions through a common function call, so that I can combine them in different ways (currently I use the straightforward way of wrapping the call as a lambdas).

However, another method is to pass that function as a non-type template parameter (this improves my performance compared to the lambda solution, because I'm constantly evaluating it), viz.

template<typename G, typename T, typename R, my_func_type<G, T, R> f>
struct MyWrapper
{
    MyWrapper(G g, T t) : g{ g }, t{ t } {}
    auto eval(int n) const
    {
        return (t.*f)(g, n);
    }

protected:
    G g;
    T t;
};

int main()
{
    AnObject g;
    TheCallingObject t;
    auto f = &TheCallingObject::callit;

    MyWrapper<AnObject, TheCallingObject, double, f> wrap(g, t)
}

But this seems a little redundant, so is it possible for the template arguments to be deduced from f?

The halfway solution I've found is:

template<auto f, typename G, typename T>
struct MyWrapper
{
    OpFuncDerivative(G g, T t) : g{ g }, t{ t } {}
    auto eval(int n) const
    {
        return (t.*f)(g, n);
    }

protected:
    G g;
    T t;
};

int main()
{
    AnObject g;
    TheCallingObject t;
    auto f = &TheCallingObject::callit;

    // it won't automatically deduce AnObject and TheCallingObject 
    // through the parameters to the constructor though!
    MyWrapper<f, AnObject, TheCallingObject> wrap(g, t) 
}

Solution

  • You can write a helper function:

    template<typename G, typename T, auto f>
    struct MyWrapper
    {
        MyWrapper(G g, T t) : g{g}, t{t}
        {}
    
        auto eval(int n) const
        {
           return (t.*f)(g, n);
        }
    
    protected:
        G g;
        T t;
    };
    
    template<auto f, typename G, typename T>
    MyWrapper<G, T, f> make_wrapper(G g, T t)
    {
        return {g, t};
    }
    

    and then use it like this:

    int main()
    {
        AnObject g;
        TheCallingObject t;
        constexpr auto f = &TheCallingObject::callit;
    
        auto wrap = make_wrapper<f>(g, t);
    }