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

假设您需要调用以下方法:

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

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

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

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

目前,我只知道两种选择:


我可以使用一个虚拟变量时,自动解包

但是,这个虚拟变量将不会被使用,它会发出一个警告,所以如果我想让这个警告保持沉默,那么代码将非常难看:

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

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

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

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

是否有另一种更简单的方法只解压元组中的一些参数?

14163 次浏览

遗憾的是,结构化绑定不支持丢弃成员,而且诸如 [[maybe_unused]]之类的属性不能应用于 结构化约束结构化约束(有人提议这样做: < strong > P0609 : “结构化绑定的属性”)。

这里有一个可能的解决办法:

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

另一种选择是使用 std::tie:

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

剪辑

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

  • 不可能进行类型推断
  • 对象必须在此之前构造,因此除非默认构造函数是平凡的,否则它不是一个好的替代方法。

您可以编写一个助手函数,它只返回 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 说的做法:

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

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

  • 如果在结构化绑定声明中至少使用了一个结构化绑定,则不会对同一声明中的其他绑定发出“未使用的变量”警告。
  • 如果没有使用结构化绑定声明中的任何绑定,则可以使用 [[maybe_unused]]属性使警告静音:

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