【问题标题】:Wrapping a templated function call in a lambda在 lambda 中包装模板化函数调用
【发布时间】:2016-07-29 16:00:27
【问题描述】:

我正在尝试编写代码来执行与此类似的操作(为演示目的编写的代码):

template <typename F, typename Args...>
inline auto runFunc(F func) -> foo
{
    return foo([func](Args... args) -> std::result_of<F>::type
        {
            // Do something before calling func
            func(args...);
            // Do something after call func
        });
}

所以基本上我正在尝试编写一个函数,该函数返回一个对象,该对象接受与模板化函数类型匹配的 lambda。显然这段代码不起作用,因为我没有定义 Args...。我将如何在 C++11 中解决这个问题?

【问题讨论】:

  • 你能提供更多关于你想要做什么的背景吗?
  • -&gt; foorunFunc(F func) 之后没有任何意义。试试decltype(foo([func](Args... args) ... ))
  • 什么是foo()?你只是想装饰func吗?
  • foo是一个班级吗?
  • foo 在这个例子中是一个类。 @templateypedef:基本上我创建了一个包含函子的任务对象(无论它是 std::function、lambda 还是其他任何东西)。但是,我希望将该函数包装在 lambda 中以做额外的工作,但让该 lambda 能够将参数转发给该函子。

标签: c++ c++11 variadic-templates


【解决方案1】:
template<class F_before, class F, class F_after>
struct decorate_func_t {
  F_before f0;
  F f1;
  F_after f2;

  template<class...Args>
  typename std::result_of<F(Args...)>::type operator()(Args&&...args)const{
    f0();
    auto r = f1(std::forward<Args>(args)...);
    f2();
    return r;
  }
};
template<class F_before, class F, class F_after>
decorate_func_t<F_before, F, F_after>
decorate_func( F_before before, F f, F_after after ){
  return {std::move(before), std::move(f), std::move(after)};
}

然后:

template <typename F, typename Args...>
inline auto runFunc(F func) -> foo
{
  return foo(decorate_func(
        []{/* Do something before calling func */},
        func,
        []{/* Do something after call func */ }
  };
}

C++11 lambda 中缺少 auto 参数,这使您可以做到最好。

在 C++14 中这是微不足道的:

template <class F>
auto runFunc(F func)
{
  return foo(
    [func](auto&&... args) // ->decltype(auto) maybe
    {
      // Do something before calling func
      auto r = func(decltype(args)(args)...);
      // Do something after call func
      return r;
    }
  );
}

请注意,许多名义上的 C++11 编译器实际上支持 lambda 上的 auto 参数。

【讨论】:

    【解决方案2】:

    您可以使用如下示例中的支撑结构:

    #include<type_traits>
    #include<cassert>
    
    struct foo {
        template<typename F>
        foo(F f) { assert(42 == f(42)); }
    };
    
    template<typename>
    struct S;
    
    template<typename R, typename... Args>
    struct S<R(*)(Args...)> {
        template <typename F>
        static auto runFunc(F func) -> foo
        {
            return foo{[func](Args... args) -> R
                {
                    // Do something before calling func
                    auto r = func(args...);
                    // Do something after call func
                    return r;
                }};
        }
    };
    
    template<typename F>
    inline auto runFunc(F func) -> foo
    {
        return S<F>::runFunc(func);
    }
    
    int f(int i) { return i; }
    
    int main() {
        runFunc(f);
    }
    

    因为我不清楚问题的背景是什么,我不确定我是否得到了您所要求的内容。
    希望上面的代码可以帮到你。

    【讨论】:

      【解决方案3】:

      仍然不确定这是您要搜索的内容,我冒着发布的风险:

      #include <iostream>
      
      struct foo
      {
          template<typename T>
          foo(T lambda)
          {
              lambda(1, 2);
          }
      };
      
      template <typename F, typename... Args>
      inline typename std::result_of<F>::type runFunc(F func)
      {
          return foo(
              [func](Args... args)
              {
                  std::cout << "Before";
                  func(args...);
                  std::cout << "After";
              }
          );
      }
      
      struct print
      {
          void operator()(int i) const
          {
              std::cout << i << std::endl;
          }
      
          void operator()(int i, int j) const
          {
              std::cout << i << " " << j << std::endl;
          }
      };
      
      int main()
      {
          runFunc<print, int, int>(print());
      }
      

      【讨论】:

      • 请注意,您的解决方案需要 C++14。您不能从 C++11 中的函数返回 lambda,您需要将其包装在命名类型中(例如:std::function,函数指针...)。
      • 哦,我刚刚意识到 lambda 不是函数返回的对象。好吧,我的第一点仍然存在
      • @KABoissonneault:哪一部分比 OP 的代码需要更多
      • 自动推导的返回类型。 OP 只使用尾随返回类型
      • @KABoissonneault:是的,感谢您的发现 - 已修复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-30
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      • 2021-11-10
      • 1970-01-01
      相关资源
      最近更新 更多