Search code examples
c++templatesfunctor

When are template arguments required in C++?


I am curious as to when template arguments are required in C++.

For example, let's define a class as

template<typename T> class Add {
    T value;
public:
    Add(T value) : value(value){};

    T operator() (T valrhs){
        return value + valrhs; 
    }
};

If we wanted to create an object of type Add using double, we would need to define it as follows to not get errors,

Add<double> add5 = Add<double>(5.0);

Lets now consider a function defined as follows,

template<typename T, typename Function> T doOperation (T data, Function f){
    return f(data);
}

In code, if one was to make a call to doOperation, no template arguments would be needed. For example,

std::cout << doOperation(5.0, add5);

would output 10. Why is it that doOperation does not require template arguments but the defining add5 required template arguments?

Also, would there be any way to define this using function pointers. I have been stuck trying to figure out how to pass a functor like this using a function pointer as a parameter variable rather than a second template argument.

Thanks, any help is appreciated.


Solution

  • In this code

    std::cout << doOperation(5.0, add5);
    

    The compiler does function-template argument deduction.

    In this line

    Add<double> add5 = Add<double>(5.0);
    

    you need to provide the template arguments since the compiler won't do class-template argument deduction.

    However, from c++17, the compiler will do class-template argument deduction, and then this compiles just fine

    Add add5(5.0);
    

    You can provide the deduction guide explicitly as well, since that may be needed in some cases

    template<typename T>  Add(T) -> Add<T>;
    

    On a side-note, your class Add looks like it could be replaced by a function-template that returns a lambda.

    template<typename T>
    auto Add (T value) { 
        return [value] (T valrhs) { 
            return value + valrhs; 
        }; 
    }
    

    The usage would then look like

    auto add5 = Add(5.0);
    std::cout << doOperation(5.0, add5);