如何从任意函数中创建一个函子?

时间:2017-04-19 19:33:11

标签: c++ c++11 templates c++17 functor

我有一堆函数,我想用作函子(也就是说,使用类型而不是传递指向函数的指针,或任何其他类型的数据)。

使用标准库或标准库+ Boost是否有优雅/惯用/标准的方法?也许以某种方式使用bind()

或者我应该采用简单化的方法(好吧,简单化),例如:

template<typename Function, Function& F, typename... Parameters>
struct functor {
    using function_type            = Function;
    using parameters_as_tuple_type = std::tuple<Parameters...>;

    auto operator() (Parameters&&... params) ->
        decltype(F(std::forward<Parameters>(params)...))
    {
        return F(std::forward<Parameters>(params)...);
    }
};

注意:

  • C ++ 11解决方案是首选,但如果您有需要甚至C ++ 17,那也很有趣。
  • 我的解决方案&#34;我认为,对于重载功能可能不起作用。

2 个答案:

答案 0 :(得分:3)

如果函数没有重载,可以在C ++ 17中执行此操作:

template <auto F>
auto to_function_object()
{
    return [](auto&&... xs) -> decltype(auto)
    { 
        return F(std::forward<decltype(xs)>(xs)...);
    };
} 

void a(int) { }

int main()
{
    auto af = to_function_object<a>();
    af(1);
}

如果函数超载,则无法将其重载集作为参数传递给另一个函数或模板。您被迫在现场手动编写包装器lambda。例如:

void foo(int)  { }
void foo(char) { }
// ...   
bar([](auto x){ return foo(x); });

N3617旨在通过引入&#34; lift&#34;来解决这个问题。操作

A. Sutton的

P0119通过允许重载集基本上生成&#34;包装器lambda&#34;以不同的方式解决问题。为你而作为参数传递。

在接受任何提案之前,您可以使用漂亮的 C ++ 14宏代替:

#define LIFT(f) \
    [](auto&&... xs) noexcept(noexcept(f(std::forward<decltype(xs)>(xs)...))) \
        -> decltype(f(std::forward<decltype(xs)>(xs)...)) \
    { \
        return f(std::forward<decltype(xs)>(xs)...); \
    }

答案 1 :(得分:1)

首先,一个固定类型的具体例子。

int foo( int );
void foo( double );

struct foo_t {
  template<class...Args>
  auto operator()(Args&&...args)const
  ->decltype( foo( std::declval<Args>()... ) )
  {  return ( foo( std::forward<Args>(args)... ) ); }
};

现在foo_t是一个通过完美转发调用foo重载的对象。

使它通用:

#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }

#define OVERLOAD_SET_TYPE(...) \
  struct { \
    template<class...Args> \
    auto operator()(Args&&...args)const \
    RETURNS( __VA_ARGS__( std::forward<Args>(args)... ) ) \
  }

所以我们可以做到

using foo_t = OVERLOAD_SET_TYPE(foo);

live example

您无法将函数的重载集作为对象进行操作;唯一的方法是文本。因此宏。

这具有完美转发的所有常见缺陷。没有办法一般避免这些不完美之处。