I have written myself the following function:
template <class Stream>
inline Stream& Print(Stream& in) { return in;}
template <class Stream, class Arg1, class... Args>
inline Stream& Print(Stream& sout, Arg1&& arg1, Args&&... args)
{
sout << arg1;
return Print(sout, args...);
}
It should make it useful to replace code like:
cout << "This took " << ns << " seconds with " << np << " packets.\n";
with
Print(cout, "This took ", ns, " seconds with ", np, " packets.\n");
And everything works fine, except that this function doesn't "tolerate" some manipulators. What is funny, only some of them. If you replace, for example, " packets.\n"
with " packets.", endl
, it will no longer compile. Although hex
or setw(20)
is fine. Where is the problem?
CodePudding user response:
I can't explain the exact reason, but if I do something like this it doesn't throw an error:
endl<char, char_traits<char>>
My guess is that it doesn't seem to be able to do template type parameter inference.
The ostream is:
using ostream = basic_ostream<char, char_traits<char>>;
CodePudding user response:
std::endl
is a function template.
So it cannot be deduced as for overloaded functions.
static_cast<std::ostream& (*)(std::ostream&)>(&std::endl)
would select correct overload.
using Manipulator = std::ostream& (*)(std::ostream&);
Print(std::cout, "This took ", ns, " seconds with ", np, " packets.", Manipulator(std::endl));
Since C 14, you might even not hard code type of stream with an helper:
template <typename T>
struct ManipulatorImpl
{
ManipulatorImpl(T t) : t(t) {}
T t;
};
template <typename T>
std::ostream& operator << (std::ostream& os, ManipulatorImpl<T> m)
{
return m.t(os);
}
template <typename T>
ManipulatorImpl<T> make_ManipulatorImpl(T t) { return {t}; }
#define Manipulator(name) make_ManipulatorImpl([](auto& os) -> decltype((name)(os)) { return (name)(os); })