C++17: Keep only some members when tuple unpacking

前端 未结 4 1212
囚心锁ツ
囚心锁ツ 2020-12-25 10:23

Let\'s imagine you need to call the following method:

std::tuple foo();

In C++17, you can call the function and unpack

相关标签:
4条回答
  • 2020-12-25 11:03

    MSVC has already fixed this in VS 15.7 Preview. The final 15.7 release should be available in the coming weeks. This means that the current logic supported by the latest releases of all major compilers is as follows:

    • If at least one of the structured bindings in a structured binding declaration is used, no "Unused variable" warning will be issued for other bindings in the same declaration.
    • If none of the bindings in a structured binding declaration are used, it is possible to silence the warning by using the [[maybe_unused]] attribute:

      [[maybe_unused]] auto [a, b, c] = foo();
    0 讨论(0)
  • 2020-12-25 11:05

    Unfortunately structured bindings do not explicitly support discarding members, and attributes such as [[maybe_unused]] cannot be applied to structured bindings (there's a proposal for that: P0609: "Attributes for Structured Bindings").

    Here's a possible solution:

    auto [a, b, c] = foo();
    (void) a; // unused
    
    0 讨论(0)
  • 2020-12-25 11:14

    Another alternative is to use an std::tie:

    int b, c;
    std::tie(std::ignore, b, c) = foo();
    

    Edit

    As mentioned in the comments, there are some issues with this approach:

    • No type inference possible
    • The objects must be constructed before, so unless the default constructors are trivial, it's not a good alternative.
    0 讨论(0)
  • 2020-12-25 11:26

    You could write a helper function that only gives you back certain indices of a std::tuple:

    template <size_t... Is, typename Tuple>
    auto take_only(Tuple&& tuple) {
        using T = std::remove_reference_t<Tuple>;
    
        return std::tuple<std::tuple_element_t<Is, T>...>(
            std::get<Is>(std::forward<Tuple>(tuple))...);
    }
    
    auto [b, c] = take_only<1, 2>(foo());
    

    Or drops the head or something:

    template <size_t... Is, typename Tuple>
    auto drop_head_impl(Tuple&& tuple, std::index_sequence<0, Is...> ) {
        return take_only<Is...>(std::forward<Tuple>(tuple));
    }
    
    template <typename Tuple>
    auto drop_head(Tuple&& tuple) {
        return drop_head_impl(std::forward<Tuple>(tuple),
            std::make_index_sequence<std::tuple_size_v<std::decay_t<Tuple>>>());
    }
    
    auto [b, c] = drop_head(foo());
    

    But the above implementations almost certainly have some lifetime complexity issues that directly using structured bindings won't - since there isn't any lifetime extension here.

    So just, do what Vittorio says:

    auto [a, b, c] = foo();
    (void)a;
    
    0 讨论(0)
提交回复
热议问题