Search code examples
c++templatesc++17overloadingoverload-resolution

How to pass a function template as a template argument?


#include <iostream>

template<typename... Args>
void print(Args const&... args)
{
    (std::cout << ... << args);
}

int main()
{
    std::cout << 1 << 2 << 3 << std::endl; // ok
    print(1, 2, 3);                        // ok
    print(1, 2, 3, std::endl);             // error! How to make it work?
}

See online demo

How to pass a function template as a template argument?


Solution

  • You will have the same issue with other io manipulators that typically are functions that take the stream as parameter, when they are templates. Though you can wrap them in a non-template callable:

    #include <iostream>
    
    template<typename... Args>
    void print(Args const&... args)
    {
        (std::cout << ... << args);
    }
        
    int main()
    {
        std::cout << 1 << 2 << 3 << std::endl; // ok
        print(1, 2, 3);                        // ok
        print(1, 2, 3, [](std::ostream& o) -> std::ostream&{ 
                   o << std::endl; 
                   return o;
        });             // no error!
    }
    

    Output:

    123
    123123
    

    The syntax is rather heavy so you might want to use a helper type, though I'll leave it to you to write that (just joking, I don't think it is trivial, but I might give it a try later ;). After pondering about it for a while, I am almost certain that there are only the two alternatives: Instantiate the function (see other answer), or wrap the call inside a lambda, unless you want to write a wrapper for each single io manipulator of course.