简体   繁体   中英

Pass multiple arguments to stream operator

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM