Reputation: 103
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;
}
Upvotes: 1
Views: 930
Reputation: 171127
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_);
}
};
Upvotes: 1