如何创建一个新变量并同时在std :: tie中使用它?

wye*_*r33 27 c++ c++11 c++14

有没有一种方法可以std::tie一次性使用和创建一个新变量?换句话说,如果函数返回a 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

}
Run Code Online (Sandbox Code Playgroud)

基本上,该函数example返回一个元组.我们已经有了一个Bar我们想要分配的变量类型,但我们需要一个新的类型变量Foo.没有std::tie,我们不需要创建一个虚拟实例Foo,但代码要求我们将所有内容放入std::tuple第一个然后除以它.有了std::tie,我们必须首先分配一个虚拟Foo,但我们没有默认的构造函数.实际上,我们假装构造函数Foo是复杂的,因此首先创建虚拟值是不可取的.最终,我们只是想分配到两个foobar,但要做到这一点分配和对分配内存Foo在同一时间.

fir*_*oot 30

此功能在C++ 17中称为结构化绑定.非常欢迎加入!

样品用法:

#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;
}
Run Code Online (Sandbox Code Playgroud)

用GCC 7.2测试-std=c++17.


wye*_*r33 12

@MikaelPersson有正确的链接.基本上,没有很好的方法可以做到这一点.虽然,有一些基于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{});
}
Run Code Online (Sandbox Code Playgroud)

然后写

// With compose
{
    auto foo = apply([&bar](auto && foo,auto && bar_) {
        bar=std::move(bar_);
        return std::move(foo);
    }, example());
}
Run Code Online (Sandbox Code Playgroud)

并且,是的,整个事情都是丑陋的,但在某些情况下确实出现了这种情况.尽管如此,正如@ MikaelPersson的链接所示,这是一个普遍的问题,而不是一个完全解决的问题.