【问题标题】:What's the difference between these two definitions of function templates?这两种函数模板的定义有什么区别?
【发布时间】:2015-08-03 19:31:38
【问题描述】:
template <typename Func, typename... Args>
  static void WraperFunc(Func func, Args &&... args) {
    SomeFunc(func, args...);
  }

template <typename Func, typename... Args>
  static void WraperFunc(Func func, Args ... args) {
    SomeFunc(func, args...);
  }

哪个更好,更推荐?或者有没有比两者都更好的替代方案?

【问题讨论】:

  • 我在问题中添加了最后一句话,允许(如在本例中)推荐 neither 方法。 “或者有没有比两者都更好的替代方案?”
  • Pre C++11,你连第一个都不能用,那你必须用后者!
  • @AaronMcDaid:你不能在 C++11 之前使用它们中的任何一个。
  • @BenjaminLindley。多哈。我忘记了varags!令人惊讶的是,几年后人们如何将某些事情视为理所当然:-)

标签: c++ templates c++11 rvalue-reference pass-by-rvalue-reference


【解决方案1】:

Args &amp;&amp; 将通过引用接受左值和右值,并使它们能够在保持其原始value category 的情况下被转发。我更喜欢那个版本(并使用std::forward)。

template <typename Func, typename... Args>
  static void WraperFunc(Func func, Args &&... args) {
    SomeFunc(func, std::forward<Args>(args)...);
    //             ^^^^^^^^^^^^ Use of forward
  }

注意std::forward 的惯用用法,它不包括Args&amp;&amp;&amp;&amp;

有许多关于std::forward 和引用折叠的机制和使用的文章、here 和关于“转发(或通用)引用”的Scott Meyers classic

【讨论】:

    【解决方案2】:

    第一个,但您需要在扩展期间使用std::forward&lt;T&gt; 转发您的参数。这允许在正确推导参数的同时扩展参数包。

    template <typename Func, typename... Args>
    static void WraperFunc(Func func, Args &&... args)
    {
        // note that we use std::forward<Args>( args )... to perfect forward our arguments
        SomeFunc(func, std::forward<Args>( args )...);
    }
    

    例如,假设您有一个声明如下的函数:

    template <typename T>
    void some_func( T& ) {}
    

    尝试将所述函数与临时值或右值一起使用将失败:

    some_func( 5 );
    

    这是因为 5 是一个常数,不能赋值给int&amp;

    【讨论】:

    • 只是一个建议,我会明确表示两者都不推荐。特别是,第一个非常糟糕,因为它给人的印象是它正在转发,由于参数中的&amp;&amp;,实际上它不是。
    • 是的,我指定应该使用 std::forward。
    【解决方案3】:

    假设您使用以下参数调用您的函数:

    void (*foo)(int, char, float) = /* ... */;
    const int i = 0;
    char j;
    WraperFunc(foo, i, j, 0.42);
    

    第一种情况,相当于调用了这个函数:

    void WraperFunc(void (*foo)(int, char, float), int i, char c, float j) { /* ... */ }
    

    第二种情况相当于调用这个函数:

    void WraperFunc(void (*foo)(int, char, float), const int& i, char& c, float&& j) { /* ... */ }
    

    如果您想转发参数同时避免复制,建议使用第二个(但请使用std::forward!)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多