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?
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));
Demo
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); })
Demo
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>>;
Related
I'm trying to differentiate between user types and primitive types in a variadic template.
I have tried overloading binary operator, but that only says that there's no fitting overload for 'user types'...
template <typename T>
void PrintParams(T t)
{
if (IsAUserType)
std::cout << typeid(t).name();
else
std::cout << t;
}
template <typename First, typename... Rest>
void PrintParams(First first, Rest... rest)
{
if (IsAUserType)
std::cout << typeid(first).name();
else
std::cout << first;
PrintParams(rest...);
}
// If you know what to do with this, then that would also be very helpful...
//Overload << operator for user types
//template <typename T>
//friend std::ostream& operator<< (std::ostream& os, T t)
//{
//
//if (std::is_fundamental<t>::value)
//std::clog << t;
//else
//std::clog << typeid(t).name();
//}
expected result for input like (class test, 3.4, "string") would be
"test3.4string"
You could split your single argument function up in two and use SFINAE to enable the correct one depending on if the argument is a fundamental type or not:
template<typename T, typename std::enable_if<std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
std::cout << t;
}
template<typename T, typename std::enable_if<!std::is_fundamental<T>::value, int>::type = 0>
void PrintParams(T t) {
std::cout << typeid(t).name();
}
template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
PrintParams(first); // ... and call the single argument version here
std::cout << ",";
PrintParams(rest...);
}
Another way would be to check if the type supports streaming using operator<< instead of checking that it's a fundamental type. That would make streaming work for classes (like std::string and user defined ones too).
#include <iostream>
#include <type_traits>
#include <typeinfo>
#include <utility>
// SFINAE support
namespace detail {
template<class>
struct sfinae_true : std::true_type {};
template<class S, class T>
static auto test_lshift(int)
-> sfinae_true<decltype(std::declval<S>() << std::declval<T>())>;
template<class S, class T>
static auto test_lshift(long) -> std::false_type;
} // namespace detail
template<class T>
struct has_ostream : decltype(detail::test_lshift<std::ostream, T>(0)) {};
// using the SFINAE support stuff
template<typename T, typename std::enable_if<has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
std::cout << "Type: " << typeid(t).name() << "\n"
<< " supports operator<< Value = " << t << "\n";
}
template<typename T, typename std::enable_if<!has_ostream<T>::value, int>::type = 0>
void PrintParams(const T& t) {
std::cout << "Type: " << typeid(t).name() << "\n"
<< " does NOT support operator<<\n";
}
template<typename First, typename... Rest>
void PrintParams(First first, Rest... rest) {
PrintParams(first);
PrintParams(rest...);
}
// example classes
class Foo { // will not support streaming
int x = 5;
};
class Bar { // this should support streaming
int x = 10;
friend std::ostream& operator<<(std::ostream&, const Bar&);
};
std::ostream& operator<<(std::ostream& os, const Bar& b) {
return os << b.x;
}
// testing
int main() {
int i = 2;
Foo f;
Bar b;
std::string s = "Hello world";
PrintParams(i, f, b, s);
}
Possible output:
Type: i
supports operator<< Value = 2
Type: 3Foo
does NOT support operator<<
Type: 3Bar
supports operator<< Value = 10
Type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
supports operator<< Value = Hello world
I think std::is_class can replace your IsAUserType.
https://en.cppreference.com/w/cpp/types/is_class
Primitive data types include integer , character , void , float etc..which are defined already inside the language i.e , user can use these data types without defining them inside the language.
User defined data types are the data types which user have to define while or before using them.
I write a variadic template to print all the arguments with recursion:
#include <iostream>
using std::ostream; using std::istream;
using std::cin; using std::cout; using std::endl;
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
if (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
}
int main(int argc, char *argv[]) {
myprint(cout, "hello");
return 0;
}
But when I compiles it with g++ -std=c++1y, it complains:
error: no matching function for call to ‘myprint(std::ostream&)’
return myprint(os, rest...);
In the function myprint, I have checked the value of sizeof...(rest). And when it is 0, it will not call myprint(os, rest...). So I don't know why it will call myprint(std::ostream&).
And I have also searched for the related question, I have found that it needs a base case. But why do I need a base case, and can't sizeof... work in a variadic template?
And for the simple indefinite recursive case:
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", "; // print the first argument
return print(os, rest...); // recursive call; print the other arguments
}
The code above can't be compiled at all for the same error.
For the if statement you used, both the statement-true and statement-false must be valid, whether the condition yields to the result of true or false.
You can use constexpr if since C++17; when the value of condition is false, the statement-true will be discarded. e.g.
if constexpr (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
If you can't use C++17, you can add another template overload for the case that the number of arguments is only one, to stop the recursion, e.g.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
LIVE
songyuanyao's answer explains why it's invalid and provides a solution for C++17. Alternatively, you could have a base case to myprint prior to that.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
Can you help me with the following problem ?
I am trying to use the variadic templates and pack expansion to write a logger. The problem is I know that operator<< must accept only two arguments - the second argument then becomes a whole pack, and I do not know how to expand 'const Args& ...rest' to 'const T& v, const Args& ...rest'
Can any guru explain how to re-write the variadic expression to achieve this goal ? The end game is to have code like:
log << "string" << 1 << 1.2;
being printed together at once.
(Please excuse the cout, it is just for example purposes. Idea is to collect all the arguments in oss_ and then print them once.).
The compiler current complains, which I understand is the issue with operator<< accepting only two arguments.
‘LogHandle& operator<<(LogHandle&, const T&, const Args& ...)’ must take exactly two argument
Here is the code:
#include <iostream>
#include <string>
#include <sstream>
class LogHandle {
public:
template<typename T>
friend LogHandle& operator<<(LogHandle& l, const T& v)
{
l.oss_ << v;
std::cout << "Value is: " << l.oss_.str().c_str();
l.oss_.str("");
l.oss_.clear();
return l;
}
template<typename T, typename... Args>
friend LogHandle& operator<<(LogHandle& l, const T& v, const Args&... rest)
{
l.oss_ << v << " ";
return l << (rest...);
}
std::ostringstream oss_;
};
int main(int, char**)
{
LogHandle log;
log << "String" << 1;
}
What you want to do is not possible exactly the way you want it, because the arity of operators is fixed—you cannot make them variadic.
However, you can instead use a proxy returned from your operator << to "collect" all the arguments in one place. Something like this:
class LogHandle
{
template<typename T>
friend LogProxy operator<<(LogHandle& l, const T& v)
{
LogProxy p(*this);
p << v;
return p;
}
void print(const std::ostringstream &oss)
{
std::cout << "Value is: " << oss.str();
}
};
struct LogProxy
{
LogHandle *handle;
std::ostringstream oss_;
LogProxy(LogHandle &l) : handle(&l) {}
LogProxy(LogProxy &&rhs) : handle(rhs.handle) { rhs.handle = nullptr; }
template <class T>
friend LogProxy& operator<< (LogProxy &p, const T &v)
{
p.oss_ << v;
return p;
}
~LogProxy()
{
if (handle) handle->print(oss_);
}
};
If I try to compile the following code I get the following compiler error (see code.) It compiles without error if std::endl is removed.
#include <iostream>
#include <sstream>
#include <utility>
namespace detail
{
template <class T>
void print(std::ostream& stream, const T& item)
{
stream << item;
}
template <class Head, class... Tail>
void print(std::ostream& stream, const Head& head, Tail&&... tail)
{
detail::print(stream, head);
detail::print(stream, std::forward<Tail>(tail)...);
}
}
template <class... Args>
void print(std::ostream& stream, Args&&... args)
//note: candidate function not viable: requires 3 arguments, but 4 were provided
{
std::stringstream ss;
detail::print(ss, std::forward<Args>(args)...);
stream << ss.rdbuf();
}
int main()
{
print(std::cout, "The answer is ", 42, std::endl);
//error: no matching function for call to 'print'
}
std::endl is a function template. When it is used, its template parameters have to be explicitly specified or deduced by the compiler.
std::ostream has an overload:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf) (basic_ostream<charT,traits>&) );
When we use
std::cout << std::endl;
the compiler deduces the types to be used for std::endl. Since you don't have the ability to fall back on automatic type deduction when calling print, you have to be explicit about which version of std::endl you want to use.
The following should work:
print(std::cout, "The answer is ", 42, std::endl<char, std::char_traits<char>>);
Update
I used the following stripped down code to track the issue:
#include <iostream>
namespace detail
{
template <class T>
void print(std::ostream& stream, const T& item)
{
stream << item;
}
}
int main()
{
// detail::print(std::cout, std::endl);
detail::print(std::cout, std::endl<char, std::char_traits<char>>);
}
I think this is because template type deduction fails if you are passing a function template. It can't deduce the parameters to instantiate endl with.
Note that the definition of endl is:
template <class charT, class traits>
basic_ostream<charT,traits>& endl (basic_ostream<charT,traits>& os);
Simpler example:
template<class U> void func(U &u) { }
template<class T>
void print(const T &item) { }
int main()
{
print(func); // error: matching function for call to 'print(<unresolved overloaded function type>)'
}
Your error messages come about because it tries various ways to match your function call to the parameter pack but none of them worked.
You could avoid the problem by defining a simple endl yourself (Live Demo):
constexpr struct endl_ {
friend std::ostream& operator << (std::ostream& os, const endl_&) {
os << '\n'; // << std::flush;
return os;
}
} endl;
template <class... Args>
void print(std::ostream& stream, Args&&... args)
{
std::stringstream ss;
std::initializer_list<int>{0, (void(ss << std::forward<Args>(args)), 0)...};
stream << ss.rdbuf();
}
int main()
{
print(std::cout, "The answer is ", 42, endl);
//error: no matching function for call to 'print'
print(std::cout, "The answer is NOT ", 13, endl);
}
I've started using C++ recently and I've felt a strong urge to
#define print(msg) std::cout << msg << std::endl
Will this perform correctly in all situations? This is the only formulation I'm aware of that will work when there's a << in msg (e.g. "foo" << myInt). Neither
#define print(msg) std::cout << (msg) << std::endl // note: parens
nor the suggested answer
template<typename T>
void print(T const& msg) {
std::cout << msg << std::endl;
}
work in this case. I also don't care about the efficiency of flushing the output with endl vs just using \n.
Since you mention you have just started using C++ recently, I would like to show you a better alternative that the language offers:
template<typename T>
void print(T const& msg)
{
std::cout << msg << std::endl;
}
It takes a single msg argument of any type, and it streams it out via std::cout.
As mentioned in the comments, std::endl does not only insert a new line but also flushes the stream. This is akin to printf flushing on \n. If you just want a new line, and you probably do, better do that explicitly:
std::cout << msg << '\n';
This is pretty subjective, but you write code once and read it many times. Other maintainers of the code will want to understand what you've written, so just write std::cout << msg << std::endl when that's what you mean. Don't try to make C++ look like another language.
Just for fun, here's two variadic C++11 implementations of print: one that inserts spaces between the arguments, and one that does not. (Live at ideone.)
#include <iostream>
namespace with_spaces {
namespace detail {
std::ostream& print(std::ostream& os) {
return os;
}
template <typename T>
std::ostream& print(std::ostream& os, T&& t) {
return os << std::forward<T>(t);
}
template <typename T, typename U, typename... Args>
std::ostream& print(std::ostream& os, T&& t, U&& u, Args&&... args) {
return print(print(os, std::forward<T>(t)) << ' ', std::forward<U>(u), std::forward<Args>(args)...);
}
}
template <typename... Args>
void print(Args&&... args) {
detail::print(std::cout, std::forward<Args>(args)...) << std::endl;
}
}
namespace without {
namespace detail {
std::ostream& print(std::ostream& os) {
return os;
}
template <typename T>
std::ostream& print(std::ostream& os, T&& t) {
return os << std::forward<T>(t);
}
template <typename T, typename... Args>
std::ostream& print(std::ostream& os, T&& t, Args&&... args) {
return print(print(os, std::forward<T>(t)), std::forward<Args>(args)...);
}
}
template <typename... Args>
void print(Args&&... args) {
detail::print(std::cout, std::forward<Args>(args)...) << std::endl;
}
}
#include <iomanip>
int main() {
std::cout << std::boolalpha;
with_spaces::print(1, "foo", new int(3), 0xFFFFFFFFFFULL, 42, 0 == 1);
without::print(1, "foo", new int(3), 0xFFFFFFFFFFULL, 42, 0 == 1);
}
It's interesting to me just how much code is necessary to accomplish what that simple one-line macro can do.
Macros are widely used, but not good practice (especially in C++) because they can hide what is really going on and make it impossible to debug your code.
Macros also bypass the type checking of the preprocessor and can lead to runtime problems.
I would suggest an inline function here if you are trying to optimize for speed.