Structured binding to replace std::tie abuse

前端 未结 3 1039
有刺的猬
有刺的猬 2020-12-10 05:54

In reading this summary of the c++17 final features I was a bit surprised by the section on structured bindings (emphasis mine):

structured bindi

相关标签:
3条回答
  • 2020-12-10 06:20

    std::tie in itself has another functionality.

    It was meant for creating a tuple with references to variables

    Creates a tuple of lvalue references to its arguments or instances of std::ignore.

    This is useful for creating on-the-fly tuples without having to copy the variables because they are references. I just take the example from cppreference for a usecase.

    bool operator<(const S& rhs) const
    {
        // compares n to rhs.n,
        // then s to rhs.s,
        // then d to rhs.d
        return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
    }
    

    Here tuples are created but they don't copy the variables but have references.

    Now because they hold references you could "hack" it to do something like this

    int a,b,c;
    std::tie(a,b,c) = std::make_tuple(1,2,3);
    

    It assigns the values of the returned tuple to the one with the references in itself.

    This is even on cpprefence just mentioned as a "note"

    std::tie may be used to unpack a std::pair because std::tuple has a converting assignment from pairs

    In c++17 they introduced "structured bindings" to take care of the scenario to assign multible variables at once. So whether it was intentional or a hack, since c++17 this usage of tie should not be necessary anymore.

    Whether std::tie was meant to be used that way or is a "hack" may be personal opinion, I guess the people who introduced std::tie know best for this. But considering how structured binding kind of replaces std::tie in that instance, they came up with a solution they think is better.

    0 讨论(0)
  • 2020-12-10 06:21

    A very noticeable difference is std::ignore. Look at the example

    std::tuple<string, string> data {"Lord", "Buddha"};
    auto [a, b] = data; //valid
    auto [ , b] = data; //not valid as the identifier is strongly required
    string y;
    std::tie( std::ignore, y ) = data; //voila
    
    0 讨论(0)
  • 2020-12-10 06:39

    I can put it simply like that:

    In a language where functions can return just one variable

    int a,b,c;
    std::tie(a,b,c) = function_returning_multiple_values();
    

    is a hack for:

    auto [a, b, c] = function_returning_multiple_values();
    

    just as in the hypothetical world where C++ would allow just one parameter for functions

    int p1, p2, p3;
    p1 = ...;
    p2 = ...;
    p3 = ...;
    
    function_taking_multiple_params(std::tie_params(p1, p2, p3));
    

    would be a hack for:

    function_taking_multiple_params(p1, p2, p3)
    

    You are so accustomed with the C++ restriction that a function can return at most one object, but in fact it is just an artificial language restriction, just as a restriction to accept at most one parameter would be an artificial language restriction.

    The std::tie is a library hack for a missing language feature. And it has some drawbacks:

    • the variables need be declared beforehand
    • the variable types must be declared explicitly
    • Inefficient or can't be used with types that are not default constructible

    Are structured bindings everything that they could have been? No, but for the most cases they are everything we need.

    What is missing?

    • Explicit type for some elements: e.g.:
    auto [a, std::string b, c] = foo();
    

    where a and c have the type deduced and b is explicit "std::string"

    • Nesting. E.g.:
    auto [a, [b1, b2], c] = foo();
    

    where the second returned object from foo is a tuple like object.

    • Language feature at the return site (bypassing std::tuple all together):
    auto foo() -> [int, int]
    

    instead of

    auto foo() -> std::tuple<int, int>
    
    • Named return objects
    auto foo() -> [int& key, int& value]
    

    ... well... wouldn't that be nice

    • and combine that with... - get ready for a cool new name - Generalized return initialization:
    auto minmax_element(It begin, It end) -> [It min_it, It max_it];
    
    auto [min = *min_it, max = *max_it] = minmax_element(...);
    
    0 讨论(0)
提交回复
热议问题