【问题标题】:Overloading Functions with std::forward Forwarding使用 std::forward 重载函数
【发布时间】:2015-11-30 14:49:53
【问题描述】:

我想知道是否可以通过对类型的一些限制进行转发,以便自动重载。例如,假设我有以下基本功能:

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

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

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&amp;A&amp;&amp;,而如果T1const B&amp;B&amp;&amp;,则可以触发第二个重载?

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

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

【问题讨论】:

    标签: c++ templates c++11 move-semantics perfect-forwarding


    【解决方案1】:

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

    是的。这个概念被称为 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&lt;&gt; 类型将是错误的,并且此重载将被丢弃。

    如果太冗长,你可以写一个别名:

    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.
    

    【讨论】:

    • 这会阻止我再次超载吗?
    • 我认为这是隐含的。那我就加吧。
    • @Tunococ 没有什么能阻止你再次超载 - 你只需要确保它不会模棱两可。
    • 谢谢。这比我预期的要好。在我看来,这种情况经常出现,所以我可能会将其添加到我的库中:)
    【解决方案2】:

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

    类似

    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&lt;T&gt;std::get&lt;T&gt;(TUPLE&amp;) 类似,但根据元组内容类型检索 T&amp;&amp;T&amp;

    【讨论】:

    • +1 用于在参数数量增加的情况下进行很好的缩放。不幸的是,当某些参数具有相同类型时将不起作用。
    • @NikkiChumakov:我们仍然可以使用my_get&lt;I, T&gt; 来检索元组中的ith T
    • 我能够创建在返回时复制元素的 my_get 实现:melpon.org/wandbox/permlink/lWtHqXgEyVrB4y8v 但我无法在其中实现完美转发,具体取决于 T1、T2 类型。想象一下函数“h(int& i) {...}”,我们在输入处有 std::tuple。 my_get 可能不应该将引用返回到中间元素,而是返回到最后一个元组的元素。但事实证明,以这种方式实现它对我来说太难了。
    • @NikkiChumakov:几乎正确,您返回 T 而不是 get 函数中的正确类型。使用decltype(auto) 有帮助:Demo
    猜你喜欢
    • 2016-08-22
    • 2017-01-31
    • 2019-04-11
    • 2013-08-24
    • 2016-11-15
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    相关资源
    最近更新 更多