【问题标题】:Forwarding a reference to a class as another type将类的引用作为另一种类型转发
【发布时间】:2017-08-28 17:50:34
【问题描述】:

我有类似下面的代码,它通过转发引用接受std::aligned_storage_t 参数,并且应该将reinterpret_cast 转换为另一种类型并将其返回给用户。

template <typename AlignedStorageType, typename TypeToReturnAs>
decltype(auto) forward_as_another_type(AlignedStorageType&& storage) {
    return *reinterpret_cast<TypeToReturnAs*>(&storage);
}

有没有什么好的方法来维护storage 在返回类型中的引用类型?例如,如果 storage 是一个右值引用,那么我希望返回类型也是一个右值引用。

【问题讨论】:

  • 返回值typename remove_reference&lt;T&gt;::type&amp;&amp; 是否与 std::move 帮助中的一样?

标签: c++ c++11 c++14 reinterpret-cast perfect-forwarding


【解决方案1】:

首先,翻转模板参数。您希望推导出 AlignedStorageType 并明确指定另一个:

template <typename TypeToReturnAs, typename AlignedStorageType>
decltype(auto) forward_as_another_type(AlignedStorageType&& storage) {
    return *reinterpret_cast<TypeToReturnAs*>(&storage);
}

接下来,您基本上想要的是有条件地转换表达式。如果AlignedStorageType&amp;&amp;X&amp;&amp;,您希望将其转换为TypeToReturnAs&amp;&amp;。如果是X&amp;,则为TypeToReturnAs&amp;。如果是X const&amp;,则为TypeToReturnAs const&amp;

我们可以添加一个类型特征来匹配引用:

template <class T, class U> struct match_reference;
template <class T, class U> struct match_reference<T&, U>       { using type = U&; };
template <class T, class U> struct match_reference<T const&, U> { using type = U const&; };
template <class T, class U> struct match_reference<T&&, U>      { using type = U&&; };
template <class T, class U> using match_reference_t = typename match_reference<T,U>::type;

然后:

template <typename TypeToReturnAs, typename AlignedStorageType>
decltype(auto) forward_as_another_type(AlignedStorageType&& storage) {
    using R = match_reference_t<AlignedStorageType&&, TypeToReturnAs>;
    return static_cast<R>(*reinterpret_cast<TypeToReturnAs*>(&storage));
}

或者,如果您仅将此作为一次性使用,则可以将该逻辑写为条件:

template <typename TypeToReturnAs, typename AlignedStorageType>
decltype(auto) forward_as_another_type(AlignedStorageType&& storage) {
    using R = std::conditional_t<
        std::is_lvalue_reference<AlignedStorageType>::value,
        TypeToReturnAs&, 
        TypeToReturnAs&&>;
    return static_cast<R>(*reinterpret_cast<TypeToReturnAs*>(&storage));
}

或:

    using R = std::conditional_t<
        std::is_lvalue_reference<AlignedStorageType>::value,
        TypeToReturnAs&, 
        TypeToReturnAs>;
    return std::forward<R>(*reinterpret_cast<TypeToReturnAs*>(&storage));

【讨论】:

  • 谢谢!这太棒了!我打算在我的代码中推断出AlignedStorageType。我只是想知道除了制作自定义特征之外是否还有其他方法可以做到这一点。
  • 你能解释一下为什么在最后一个例子中std::conditional_t的第三个参数是TypeToReturnAs而不是TypeToReturnAs&amp;&amp;吗?
  • @Curious 这两种方式都一样,因为forward&lt;T&gt; 会返回一个T&amp;&amp;。它只是更短一点,更适合forward 的常见用法(例如,您通常不写std::forward&lt;T&amp;&amp;&gt;(x))。
  • 但是std::forward 有两个重载,一个接受右值,一个接受左值(因为一个接受左值引用,另一个接受右值引用),那么不会最后一个例子总是与左值引用匹配?因为来自 reinterpret_cast 的取消引用值不是右值(xvalue 或 prvalue)。还是我错了?
  • @Curious 是的,它将始终与左值引用匹配。与编写std::forward&lt;T&gt;(x) 时的方式相同,无论您是否移动,您都在调用左值引用重载,因为x 始终是左值。
猜你喜欢
  • 2012-03-28
  • 1970-01-01
  • 2020-12-02
  • 2011-09-24
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
相关资源
最近更新 更多