如何创建一个新变量并同时在std::tie中使用它?
How to create a new variable and use it in std::tie at the same time?
有没有什么好的方法可以使用std::tie
一次性创建一个新变量?换句话说,如果一个函数 returns 一个 std::tuple
并且我们想要最终将结果分解成单独的组件,有没有一种方法可以在不事先定义变量的情况下进行这些赋值?
例如,考虑以下代码:
#include <tuple>
struct Foo {
Foo(int) {}
};
struct Bar{};
std::tuple <Foo,Bar> example() {
return std::make_tuple(Foo(1),Bar());
}
int main() {
auto bar = Bar {};
// Without std::tie
{
auto foo_bar = example();
auto foo = std::get<0>(std::move(foo_bar));
bar = std::get<1>(std::move(foo_bar));
}
// With std::tie
#if 0
{
// Error: no default constructor
Foo foo;
std::tie(foo,bar) = example();
}
#endif
}
基本上,函数example
returns 一个元组。我们已经有一个 Bar
类型的变量要分配给它,但是我们需要一个 Foo
类型的新变量。没有std::tie
,我们不需要创建Foo
的虚拟实例,但代码要求我们先将所有内容放入std::tuple
,然后再划分它。对于 std::tie
,我们必须首先分配一个虚拟 Foo
,但我们没有默认构造函数来这样做。实际上,我们假装 Foo
的构造函数很复杂,因此首先创建一个虚拟值是不可取的。最终,我们只想分配给 foo
和 bar
,但希望同时为 Foo
分配内存。
@MikaelPersson 有权利 link。基本上,没有很好的方法可以做到这一点。不过,有一些基于 N3802 的巧妙方法。即,使用
// This comes from the N3802 proposal for C++
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices =
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
}
然后写
// With compose
{
auto foo = apply([&bar](auto && foo,auto && bar_) {
bar=std::move(bar_);
return std::move(foo);
}, example());
}
而且,是的,这整件事都很丑陋,但在我遇到的某些情况下确实出现了这种情况。然而,正如@MikaelPersson 的 link 所示,这是一个普遍问题,尚未完全解决。
此功能在 C++17 中称为 structured bindings。非常欢迎补充!
示例用法:
#include <iostream>
#include <tuple>
int main()
{
auto tuple = std::make_tuple(1, 'a', 2.3);
// unpack the tuple into individual variables declared at the call site
auto [ i, c, d ] = tuple;
std::cout << "i=" << i << " c=" << c << " d=" << d << '\n';
return 0;
}
在 GCC 7.2 中测试 -std=c++17
。
有没有什么好的方法可以使用std::tie
一次性创建一个新变量?换句话说,如果一个函数 returns 一个 std::tuple
并且我们想要最终将结果分解成单独的组件,有没有一种方法可以在不事先定义变量的情况下进行这些赋值?
例如,考虑以下代码:
#include <tuple>
struct Foo {
Foo(int) {}
};
struct Bar{};
std::tuple <Foo,Bar> example() {
return std::make_tuple(Foo(1),Bar());
}
int main() {
auto bar = Bar {};
// Without std::tie
{
auto foo_bar = example();
auto foo = std::get<0>(std::move(foo_bar));
bar = std::get<1>(std::move(foo_bar));
}
// With std::tie
#if 0
{
// Error: no default constructor
Foo foo;
std::tie(foo,bar) = example();
}
#endif
}
基本上,函数example
returns 一个元组。我们已经有一个 Bar
类型的变量要分配给它,但是我们需要一个 Foo
类型的新变量。没有std::tie
,我们不需要创建Foo
的虚拟实例,但代码要求我们先将所有内容放入std::tuple
,然后再划分它。对于 std::tie
,我们必须首先分配一个虚拟 Foo
,但我们没有默认构造函数来这样做。实际上,我们假装 Foo
的构造函数很复杂,因此首先创建一个虚拟值是不可取的。最终,我们只想分配给 foo
和 bar
,但希望同时为 Foo
分配内存。
@MikaelPersson 有权利 link。基本上,没有很好的方法可以做到这一点。不过,有一些基于 N3802 的巧妙方法。即,使用
// This comes from the N3802 proposal for C++
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}
template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices =
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>(t), Indices{});
}
然后写
// With compose
{
auto foo = apply([&bar](auto && foo,auto && bar_) {
bar=std::move(bar_);
return std::move(foo);
}, example());
}
而且,是的,这整件事都很丑陋,但在我遇到的某些情况下确实出现了这种情况。然而,正如@MikaelPersson 的 link 所示,这是一个普遍问题,尚未完全解决。
此功能在 C++17 中称为 structured bindings。非常欢迎补充!
示例用法:
#include <iostream>
#include <tuple>
int main()
{
auto tuple = std::make_tuple(1, 'a', 2.3);
// unpack the tuple into individual variables declared at the call site
auto [ i, c, d ] = tuple;
std::cout << "i=" << i << " c=" << c << " d=" << d << '\n';
return 0;
}
在 GCC 7.2 中测试 -std=c++17
。