转发对类的引用作为另一种类型

时间:2017-04-03 18:27:41

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

我有以下代码通过转发引用接受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在返回类型中的引用类型?例如,如果存储是右值引用,那么我希望返回类型也是右值引用。

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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));