Search code examples
c++templatesc++11first-class-functions

How can I pass a function to a templated function A which may have a different signature based on another parameter to A?


I would like to create a template using a type, as well as passing a function which has a template argument which contains that type.

Here is what I currently have:

#include <iostream>

void fooRef(int& ref) { std::cout << "In ref" << std::endl; }
void fooPtr(int* ptr) { std::cout << "In ptr" << std::endl; }

template<typename T, typename F>
void Print(T arg, F func) {
    //DoABunchOfStuff();
    func(arg);
    //DoSomeMoreStuff();
}

int main() {
    int x = 5;
    int& ref = x;

    Print<int*, void(*)(int*)>(&x, &fooPtr);
    Print<int&, void(*)(int&)>(ref, &fooRef);
}

This works, but I feel like there may be some extra verbosity to the caller of the function. Ideally I want the call to look something like:

Print<int*, fooPtr>(ptr);
Print<int&, fooRef>(ref); 

Is there a way to simplify the calls to the Print function?


Solution

  • Is there a way to simplify the calls to the Print function?

    Yes. What you do is not specify the template types at all. Function templates go through a process call template argument deduction. In this process the parameters passed to the function have their type deduced and the compiler tries to match it up to the template parameters. if it works then the function is stamped out and the compiler continues on. So for you code if we used

    int main() {
        int x = 5;
        int& ref = x;
    
        Print(&x, &fooPtr);
        Print(std::ref(ref), &fooRef);
    }
    

    Then we get

    In ptr
    In ref
    

    Live Example

    In the second call I used std::ref so it would actually pass ref by reference. Otherwise it would make a copy of whatever ref refers to.