首页 > 解决方案 > 如何在模板化函数(c++)的返回类型中保留引用?

问题描述

我有一个名为 TypeHolder 的结构,它基本上是一个围绕类型 T 的薄包装器:

template <typename T>
struct TypeHolder {};

现在,我想创建一个函数,它接受任何类型的对象,如果对象是 TypeHolder(T 是 TypeHolder 的类型),则将该对象转换为 T。如果不是,该函数应该只保留对象的原始类型。

我试图定义这样的函数:

template <typename T>
auto castToObjIfTypeHolder(T obj, char) -> T; // This overload is called if T is not a TypeHolder
template <typename T>
auto castToObjIfTypeHolder(TypeHolder<T> obj, int) -> T; // This overload is called if T is a TypeHolder
// You call the function like so: castToObjIfTypeHolder(obj, 0), which will prefer the second overload by default (as int is a better match for 0 than char).
// However, when i called the function with an int& the return type is int but I would like it to be int& instead.

重载决议非常有效,每次都会调用正确的函数。但是,当调用第一个重载时,来自原始类型 T 的任何引用都将被剥离。例如,如果我传递一个类型为 的对象int&,则返回类型为int。同样,如果我传递一个类型为 的对象int&&,则返回类型为int

我想保留引用,即当我传递一个类型的对象时int&,返回类型应该是int&.

为什么第一个重载会删除引用以及如何保留引用?

标签: c++referencec++20

解决方案


如果您只想检索类型,则可以使用结构和(部分)专业化:

template <typename T>
struct UnderlyingTypeIfTypeHolder
{
    using type = T;
};

template <typename T>
struct UnderlyingTypeIfTypeHolder<TypeHolder<T>>
{
    using type = T;
};

演示

如果你想调度代码,我会选择 C++17 if constexpr

template <typename T>
decltype(auto) castToObjIfTypeHolder(T&& obj)
{
    if constexpr (is_TypeHolder_v<std::decay_t<T>>) {
        return std::decay_t<T>::type{};
    } else {
        return std::forward<T>(obj);
    }
}

注意:特征is_TypeHolder可以按照上述方法完成。


推荐阅读