C ++ 17:在元组解包时只保留一些成员

时间:2018-05-04 13:39:30

标签: c++ tuples c++17

让我们想象您需要调用以下方法:

std::tuple<int, int, int> foo();

在C ++ 17中,您可以调用该函数并将元组解压缩为一行:

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

现在,我该如何继续只存储bc并放弃a

目前,我只知道两个选项:

1 - 我可以在自动解压缩时使用虚拟变量

然而,虚拟变量将被取消并且它将发出警告,因此如果我想要保持警告,那么代码将非常令人不愉快:

#pragma warning(push)
#pragma warning(disable:4101)
// ReSharper disable once CppDeclaratorNeverUsed
auto [_, b, c] = foo();
#pragma warning(pop)

2 - 我可以存储整个元组并使用std::get来检索对我需要的唯一变量的引用。代码不那么令人不愉快,但语法也不那么简单。

此外,对于我们希望保留在元组中的每个新值,此代码的大小会增加一行。

auto tuple = foo();
int b = std::get<1>(tuple);
int c = std::get<2>(tuple);

是否有另一种更直接的方法来解包元组中的一些参数?

4 个答案:

答案 0 :(得分:42)

另一种方法是使用std::tie

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

修改

正如评论中所提到的,这种方法存在一些问题:

  • 无法进行类型推断
  • 之前必须构造对象,因此除非默认构造函数是微不足道的,否则它不是一个好的选择。

答案 1 :(得分:39)

不幸的是structured bindings没有明确支持丢弃成员,[[maybe_unused]]等属性无法应用于结构化绑定(其中有一个提案:{{ 3}})。

这是一个可能的解决方案:

auto [a, b, c] = foo();
(void) a; // unused

答案 2 :(得分:20)

您可以编写一个辅助函数,只返回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());

或掉头或其他东西:

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());

但是上面的实现几乎肯定会有一些终身复杂性问题直接使用结构化绑定不会 - 因为这里没有任何生命周期扩展。

所以,做一下Vittorio says

auto [a, b, c] = foo();
(void)a;

答案 3 :(得分:5)

MSVC在VS 15.7预览版中已经fixed了。最终的15.7版本将在未来几周内发布。这意味着所有主要编译器的最新版本支持的当前逻辑如下:

  • 如果使用结构化绑定声明中的至少一个结构化绑定,则不使用&#34;未使用的变量&#34;将在同一声明中为其他绑定发出警告。
  • 如果未使用结构化绑定声明中的任何绑定,则可以使用[[maybe_unused]]属性使警告静音:

    [[maybe_unused]] auto [a, b, c] = foo();