10
#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?

xmllmx
  • 39,765
  • 26
  • 162
  • 323

3 Answers3

10

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.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
7

Here a way:

print(1, 2, 3, std::endl<char, std::char_traits<char>>);

Consider using '\n' instead.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
  • 2
    [`'\n'` does not flush buffer, but `std::endl` does!](https://stackoverflow.com/questions/213907/stdendl-vs-n). What if OP wants that! Also have a look: [Can I take the address of a function defined in standard library?](https://stackoverflow.com/questions/55687044/can-i-take-the-address-of-a-function-defined-in-standard-library). Therefore, packing into a lambda is the better way. – Const Aug 05 '21 at 13:56
  • 2
    You mostly only want a \n and if you also want to flush the buffer, do that explicitly. That is why I said "consider using" not "you should" – Aykhan Hagverdili Aug 05 '21 at 15:00
  • About taking address of the function, that's how "std::endl" works. – Aykhan Hagverdili Aug 05 '21 at 15:01
  • [You shouldn't take the address of a standard library function (or template)](https://stackoverflow.com/a/55687045/5376789). – xskxzr Aug 06 '21 at 02:30
  • 2
    @xskxzr: That [doesn’t apply to the unary manipulators](https://en.cppreference.com/w/cpp/language/extending_std#Addressable_functions). – Davis Herring Aug 06 '21 at 03:27
5

You cannot take address of most standard functions (see can-i-take-the-address-of-a-function-defined-in-standard-library).

Fortunately, io-manipulator is part of the exception (See Addressable_functions).

std::endl is a template function, so you would have to select the correct overload.

using print_manip_t = std::ostream& (*) (std::ostream&);

print(1, 2, 3, print_manip_t{std::endl});
print(1, 2, 3, static_cast<print_manip_t>(std::endl));
print(1, 2, 3, static_cast<std::ostream& (*) (std::ostream&)>(std::endl));

else you have to specify which one you want

print(1, 2, 3, std::endl<char, std::char_traits<char>>);

or wrap it

print(1, 2, 3, [](std::ostream& o) -> std::ostream&{ return o << std::endl; });

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    Also, would be a good suggestion: "[Can I take the address of a function defined in standard library?](https://stackoverflow.com/questions/55687044/can-i-take-the-address-of-a-function-defined-in-standard-library)." – Const Aug 05 '21 at 14:03