The generic form that works with std::wostream as well:
template <typename CharT, typename Traits>
std::basic_ostream<CharT, Traits> &
Print(std::basic_ostream<CharT, Traits> &out)
{
    return out;
}
template <typename CharT, typename Traits, typename T>
std::basic_ostream<CharT, Traits> &
Print(std::basic_ostream<CharT, Traits> &out, T &&t)
{
    return (out << std::forward<T>(t));
}
template <typename CharT, typename Traits, typename T, typename... Args>
std::basic_ostream<CharT, Traits> &
Print(std::basic_ostream<CharT, Traits> &out, T &&t, Args &&...args)
{
    return Print( Print(out, std::forward<T>(t)), std::forward<Args>(args)... );
}
I couldn't make it work with with std::endl in the common case (it is possible to handle std::endl in specific cases like when it is the first or the last argument, but not in the common case, especially if there are multiple std::endl in a single call). You can still use '\n' instead or use std::endl with template arguments specified if you really need std::endl:
Print(std::cout, "hello world", std::endl<char, std::char_traits<char>>);
The differences between std::endl and '\n'
- If the stream is working in binary mode then '\n'isn't converted to the line ending format of the platform the code compiled for (but in text mode it is still converted).
- '\n'doesn't flush the stream with- std::flush(but it still flushes the- std::coutif the program is running on a terminal)
So for me it is OK to use '\n', or maybe even preferred.
Using some other IO manipulators is still possible:
Print(std::cout, std::hex, 11, '\n');
I also implemented sprintf counterpart that works with variadic templates and returns std::string:
template <typename CharT = char, typename Traits = std::char_traits<CharT>, typename... Args>
std::basic_string<CharT, Traits>
SPrint(Args &&...args)
{
    std::basic_stringstream<CharT, Traits> ss;
    Print(ss, std::forward<Args>(args)...);
    return std::move(ss.str());
}
Here is some demos.