【问题标题】:Default argument for a functor in a templated parameter模板化参数中仿函数的默认参数
【发布时间】:2019-09-04 15:08:45
【问题描述】:

我想在我的函数中为函子参数设置一个默认 lambda。

我知道可以像这样使用structoperator()

struct AddOne {
    int operator()(int a) {
        return a+1;
    }
};

template <typename Functor = AddOne>
int run_old(int x, Functor func = AddOne()) 
{
    return func(x);
}

但我想知道,考虑到 c++14/17/20 中标准的变化,是否有一种现代方式来完成这项工作?

template <typename Functor>
int run_new(int x, Functor func = [](int a){ return a+1; }) 
{
    return func(x);
}

我不确定将使用什么作为 Functor 的默认类型,或者是否有我不知道的语法。

https://godbolt.org/z/Hs6vQs

【问题讨论】:

  • "现代方式" 旧方式有什么问题? struct 方法在函数站点更容易阅读。
  • 旧方式中,您可能不希望以这种方式同时提供默认模板和函数参数:wandbox.org/permlink/PtSwiQwsNDyDrshu。请改用Functor func = Functor()

标签: c++ lambda c++14 c++17 template-argument-deduction


【解决方案1】:

C++11 你已经可以这样做了:

template <typename Functor = int(int)>
int run_new(int x, Functor func = [](int a){ return a+1; }) 
{
    return func(x);
}

【讨论】:

  • 仅适用于非捕获 lambda,不是吗? (与所问的问题无关)
  • @foreknownas_463035818:如果你传递一个捕获的 lambda,那么模板函数会推断出这个 lambda 的类型,从而覆盖默认类型 int(int)
  • @foreknownas_463035818 我认为您无法在此上下文中捕获任何内容,因为 lambda 用作默认参数。
  • @foreknownas_463035818 无论如何您都无法捕获全局。捕获需要自动存储。
  • 请注意,GCC 和 Clang 足够聪明,可以内联 lambda 调用,即使它被转换为函数指针。 godbolt.org/z/nl4qEj
【解决方案2】:

只需为此添加一个重载。

template <typename Functor>
int run_new(int x, Functor func) 
{
    return func(x);
}

int run_new(int x) 
{
    return run_new(x, [](int a){ return a+1; });
}

让您可以解决无法将 lambda 表达式作为默认函数参数的问题。

【讨论】:

    【解决方案3】:

    不是很“现代”,但您可以使用普通的旧重载和仅采用单个参数的非模板方法:

    int run_new(int x) 
    {
        return func(x,[](int a){ return a+1;});  // calls the template overload
    }
    

    【讨论】:

      【解决方案4】:

      只是为了好玩,在 C++20 中,我们有 (1) 未计算上下文中的 lambda 和 (2) 没有捕获的 lambda 是默认可构造的。结合这两者,你会得到:

      template <typename Functor = decltype([](int a){ return a+1; })>
      int run_new(int x, Functor func = {})
      {
          return func(x);
      }
      

      Obligatory godbolt.

      【讨论】:

        【解决方案5】:

        除了其他问题,您甚至可以避免使用模板:

        int run_new(int x, std::function<int(int)> func = [](int a){ return a + 1; })
        {
           return func(x);
        }
        

        【讨论】:

        • 请注意,您确实会为此产生费用。 std::function 使用类型擦除,因此您可以进行动态分配,并且很可能会失去内联代码的能力。
        • @NathanOliver GCC 和 Clang 似乎都足够聪明,可以为 f 生成相同的内联汇编代码,这是最小的:godbolt.org/z/uuEeNE。不得不承认我很惊讶。
        • @DanielLangr 但是现在函子必须是可复制的
        • @Artyer 这就是缺点。优点是不需要在头文件中暴露函数定义。
        【解决方案6】:

        我能想象的最好的通过变量传递

        static constexpr auto defFunc = [](int a){ return a+1; };
        
        template <typename Functor = decltype(defFunc)>
        int run_new(int x, Functor func = defFunc) 
        {
            return func(x);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-11
          • 2020-07-10
          • 2012-03-26
          • 1970-01-01
          相关资源
          最近更新 更多