结构化绑定,将它们传递给其他函数和值类别

问题描述 投票:0回答:1

我的主要问题是:

如何正确编写应用结构化绑定并将结果变量传递给函数的函数,同时正确保留引用、常量性等...

在代码中

template<?>
<?> call_with( ? && object, ? && function ){
    auto ? [ x1, x2, x3 ] = ?( object );
    return ?( (?(function))( ?(x1), ?(x2), ?(x3) );
}

在这种情况下,我有以下小问题

(1),

auto [ x1, x2, x3 ] = ...
vs
auto & [ x1, x2, x3 ] = ...
vs
auto && [ x1, x2, x3 ] = ...
实际上有什么区别。在这种情况下应该使用哪个?

(2),如果

object
作为右值传递,那么将
x1
x2
x3
也视为右值是否有意义? (对于可能的类型,他们可以有
T
T &
T &&
T const &
等)。 类似的东西也适用于左值吗?这将如何实现?

(3),

function
的“正确”输入是什么?在示例中我将其作为转发参考。

(4)是否还需要进行其他操作?

  • 在结构化绑定声明之前
    object
    移动或转发
  • 同样适用于
    function
  • 类似的返回值
    function

(5) 如何定义返回类型而不丢失

function
返回的潜在引用?

c++ perfect-forwarding structured-bindings
1个回答
0
投票

前言

这个答案是为了与

std::apply
一致,使得元组的元素通过
std::apply
call_with
以相同的方式转发。这似乎是解决这个问题的最明智的方法,因为两个函数的行为相似,但使用不同的机制(类似元组与结构化绑定)。

解决方案

template< typename T, typename U >
struct copy_cref { using type = U; };
template< typename T, typename U >
struct copy_cref< T &, U > { using type = U &; };
template< typename T, typename U >
struct copy_cref< T const &, U > { using type = U const &; };
template< typename T, typename U >
struct copy_cref< T &&, U > { using type = U &&; };
template< typename T, typename U >
struct copy_cref< T const &&, U > { using type = U const &&; };

template<typename T,typename U>
using copy_cref_t = typename copy_cref<T,U>::type;

template< typename F, typename T >
constexpr decltype(auto) call_with( F && f, T && t )
{
    auto && [ x1, x2, x3, x4 ] = t;

    return std::invoke( 
        std::forward< F >( f ),
        std::forward< copy_cref_t< decltype( t ), decltype( x1 ) > >( x1 ),
        std::forward< copy_cref_t< decltype( t ), decltype( x2 ) > >( x2 ),
        std::forward< copy_cref_t< decltype( t ), decltype( x3 ) > >( x3 ),
        std::forward< copy_cref_t< decltype( t ), decltype( x4 ) > >( x4 )
    );
}

解释

std::apply

如果我们看一下

std::apply

的仅说明实现
template<class F,class Tuple, std::size_t... I>
constexpr decltype(auto)
    apply-impl(F&& f, Tuple&& t, std::index_sequence<I...>) // exposition only
{
    return INVOKE(std::forward<F>(f), std::get<I>(std::forward<Tuple>(t))...);
}

我们看到通过在转发的元组上使用

INVOKE
将元素传递给
std::get
。与此处相关的
std::get
声明是

template< std::size_t I, class... Types >
std::tuple_element<I, tuple<Types...>>::type& get( tuple<Types...>& t ) noexcept;

template< std::size_t I, class... Types >
std::tuple_element<I, tuple<Types...>>::type&& get( tuple<Types...>&& t ) noexcept;

template< std::size_t I, class... Types >
const std::tuple_element<I, tuple<Types...>>::type& get( const tuple<Types...>& t ) noexcept;

template< std::size_t I, class... Types >
const std::tuple_element<I, tuple<Types...>>::type&& get( const tuple<Types...>&& t ) noexcept;

观察

const
和引用只是从元组类型转移到元素类型。与首先删除引用然后设置引用的
std::forward_like
不同,它使用引用折叠规则
T && &
->
T &
。这是
copy_cref
实现的行为。

对于我的具体问题。

(1) 我仍然没有找到对差异的令人满意的解释。看来

auto && [...]
是最通用的版本了。

(2)

std::apply
采取的方法似乎是最安全的选择。我假设当您存储对存储在同一结构/元组中的数据的左值和右值引用时会出现问题。因此,答案是“视情况而定”。

(3,4,5) 不知道,我只是复制了

std::apply
。请参阅相关资源。

相关资源

https://en.cppreference.com/w/cpp/utility/apply
https://en.cppreference.com/w/cpp/utility/functions/invoke
https://en.cppreference.com/w/cpp/utility/tuple/get

结构化绑定和转发引用可以很好地混合吗?
何时使用 std::invoke 而不是简单地调用可调用对象?
从函数返回时,auto 和 decltype(auto) 有什么区别?

© www.soinside.com 2019 - 2024. All rights reserved.