使用 std::转发的重载函数

Overloading Functions with std::forward Forwarding

本文关键字:重载 函数 转发 std 使用      更新时间:2023-10-16

我想知道是否可以在对类型进行一些约束的情况下进行转发,以便可以自动重载。例如,假设我有以下基本函数:

int f(A a, B b)
{
    return g(a) + h(b);
}

其中AB是包含所有正确复制和移动构造函数的类,gh是函数,每个函数都有两个重载:int g(const A&)int g(A&&)h相同。转发ab的通常方法是 f

template <typename T1, typename T2>
int f(T1&& a, T2&& b)
{
    return g(std::forward<T1>(a)) + h(std::forward<T2>(b));
}

但是,我还想添加另一种使用此功能的方法:

int f(B b, A a)
{
    return g(a) + h(b);
}

如果我尝试在此重载中使用转发,则生成的模板函数如下所示:

template <typename T1, typename T2>
int f(T1&& b, T2&& a)
{
    return g(std::forward<T1>(a)) + h(std::forward<T2>(b));
}

这将与第一个模板冲突。

所以我的问题是,当我编写一个用于转发的模板函数时,我是否可以约束T1T2,以便在第一次重载中,T1只能绑定到const A&A&&,而第二次重载可以在T1 const B&B&&时触发?

如果没有这样的机制,我需要显式编写 8 个重载。

注意:我想我可以用这个玩具示例中type_traits的一些模板做一些事情(有点讨厌(,但我首先想知道是否有更简单的方法,因为实际上,重载可能比这个玩具示例更不同。

我可以约束 T1 和 T2 以便第一次重载时,T1 只能绑定到 const A&A&& 吗?

是的。这个概念被称为SFINAE(替换失败不是错误(,基本上看起来像这样:

template <typename T1, typename T2,
          std::enable_if_t<std::is_same<A, std::decay_t<T1>>::value>* = nullptr
          >
int f(T1&& a, T2&& b);

如果T1没有"衰减"到A,那么enable_if_t<>类型将是格式不正确的,并且这个重载将被抛弃。

如果太冗长,您可以编写别名:

template <typename From, typename To>
using enable_if_decays = std::enable_if_t<std::is_same<To, std::decay_t<From>>::value>;
 template <typename T1, typename T2,
           enable_if_decays<T1, A>* = nullptr>
 int f1(T1&& a, T2&& b);
 template <typename T1, typename T2,
           enable_if_decays<T1, B>* = nullptr>
 int f1(T1&& b, T2&& a);
 // etc.

另一种可能性是根据其类型检索正确的参数

类似的东西

template <typename T1, typename T2>
int f(T1&& t1, T2&& t2)
{
    auto t = std::forward_as_tuple(t1, t2);
    return g(my_get<A>(t)) + h(my_get<B>(t));
}

my_get<T>类似于std::get<T>(TUPLE&),但检索T&&T&,具体取决于元组内容类型。