I have a class, let's call it Sample
with variadic template arguments. This class contains a function run(Args... args)
. This class also implements a stream operator that calls this function.
The class looks like this:
template<typename ...Args>
class Sample
{
void run(Args... args)
{
// do something
}
Sample& operator<<(const tuple<Args...>& args)
{
run(unpack_somehow(args)...);
return *this;
}
};
Now I want to use the stream operator to concat multiple calls, by passing the arguments via the brace initialization of tuples:
void main()
{
Sample<int, string, int> s;
// doesn't work :(
s << {1, "msg", 2} << {1, "msg", 2};
}
I know I could just write make_tuple(1, "msg", 2)
and it would work, but I'm looking for a solution that doesn't need additional function calls like make_tuple
.
Is there a way to implement such a feature that I can pass the arguments in braces (or maybe by comma separation by overloading the comma operator)?
When you use the line s << {1, "msg", 2} << {1, "msg", 2};
it does not provide the C++ compiler with enough information to deduce what you mean by those initializer lists.
Unless you give a hint to compiler (use a make_tuple
or pass an actual tuple
variable) it won't know what you mean and won't be able to call the appropriate operator<<()
.
Looks like you are out of luck. This cannot be done in the way your question is posted.
Initializer-lists are not enabled on the side of an operator.
They are not enabled on the right-hand side because they are not enabled on the left-hand side, and they are not enabled on the left-hand side because that would have posed too big a challenge for parsers.
As to the reasons for this , a draft/discussion paper N2215 by Stroustrup and Dos Reis from 2007 provides a lot of insight into many of the issues with initializer-lists in various contexts. Specifically, there is a section on binary operators (section 6.2):
Consider more general uses of initializer lists. For example:
v = v+{3,4}; v = {6,7}+v;
When we consider operators as syntactic sugar for functions, we naturally consider the above equivalent to
v = operator+(v,{3,4}); v = operator+({6,7},v);
It is therefore natural to extend the use of initializer lists to expressions. There are many uses where initializer lists combined with operators is a “natural” notation.
However, it is not trivial to write a LR(1) grammar that allows arbitrary use of initializer lists. A block also starts with a { so allowing an initializer list as the first (leftmost) entity of an expression would lead to chaos in the grammar.
It is trivial to allow initializer lists as the right-hand operand of binary operators, in subscripts, and similar isolated parts of the grammar. The real problem is to allow;a={1,2}+b;
as an assignment-statement without also allowing;{1,2}+b;
. We suspect that allowing initializer lists as right-hand, but nor [sic] as left-hand arguments to most operators is too much of a kludge, [...]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.