c++templatesinheritancetemplate-argument-deduction

Deduce template parameter based on function to override of a base class


Let's start with some code.

class intClass {
public:
    virtual ~intClass() = default;

    virtual int sum(int a, int b) const = 0;
};

class doubleClass {
public:
    virtual ~doubleClass() = default;

    virtual double sum(double a, double b) const = 0;
};

template<typename T, typename C>
class sumClass : public C {
public:
    T sum(T a, T b) const override {
        return a + b;
    }
};

int main() {
    sumClass<int, intClass> intSum;
    sumClass<double, doubleClass> doubleSum;
    return 0;
}

Assume that intClass and doubleClass cannot be changed.

I'd like to remove the template parameter T from sumClass. Is it possible to deduce T based on the signature of the sum function in the base class instead? We can use up to C++20.

Overall, I want my main function to look like this:

int main() {
    sumClass<intClass> intSum;
    sumClass<doubleClass> doubleSum;
    return 0;
}

Solution

  • You can create a trait to deduce the expected type:

    template <typename Sig>
    struct sumTrait;
    
    template <typename T, typename C>
    struct sumTrait<T (C::*)(T, T) const>
    {
        using type = T;
    };
    

    Then use that trait:

    template<typename C>
    class sumClass : public C {
        using T = typename sumTrait<decltype(&C::sum)>::type;
    public:
        T sum(T a, T b) const override {
            return a + b;
        }
    };
    

    Demo