C++ 如何从任意函数中生成函子?

C++ 如何从任意函数中生成函子?,c++,c++11,templates,c++17,functor,C++,C++11,Templates,C++17,Functor,我有一堆函数,我想用作函子(也就是说,使用类型而不是传递指向函数的指针或任何其他类型的数据) 使用标准库或标准库+Boost是否有一种优雅的/惯用的/标准的方法来实现这一点?也许以某种方式使用了bind() 或者我应该选择一些简单化的东西(嗯,有点简单化),比如: 模板 结构函子{ 使用函数类型=函数; 使用参数\u作为\u tuple\u type=std::tuple; 自动运算符()(参数和…参数)-> decltype(F(标准::转发(参数)…) { 返回F(标准::转发(参数)…);

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

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

或者我应该选择一些简单化的东西(嗯,有点简单化),比如:

模板
结构函子{
使用函数类型=函数;
使用参数\u作为\u tuple\u type=std::tuple;
自动运算符()(参数和…参数)->
decltype(F(标准::转发(参数)…)
{
返回F(标准::转发(参数)…);
}
};
注意事项:

  • C++11解决方案是首选,但如果您有一些甚至需要C++17的东西,这也很有趣
  • 我认为,对于重载函数,我的“解决方案”可能不起作用

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

template <auto F>
auto to_function_object()
{
    return [](auto&&... xs) -> decltype(auto)
    { 
        return F(std::forward<decltype(xs)>(xs)...);
    };
} 
旨在通过引入“提升”操作员来解决此问题

通过允许重载集在作为参数传递时基本上为您生成“包装lambda”,Sutton以不同的方式解决了这个问题

在这些建议被接受之前,您可以使用漂亮的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)...); \
    }
定义提升(f)\ []无异常(无异常(f(std::forward(xs)…))\ ->decltype(f(std::forward(xs)…)\ { \ 返回f(std::forward(xs)…)\ }
如果函数没有重载,可以在C++17中执行此操作:

template <auto F>
auto to_function_object()
{
    return [](auto&&... xs) -> decltype(auto)
    { 
        return F(std::forward<decltype(xs)>(xs)...);
    };
} 
旨在通过引入“提升”操作员来解决此问题

通过允许重载集在作为参数传递时基本上为您生成“包装lambda”,Sutton以不同的方式解决了这个问题

在这些建议被接受之前,您可以使用漂亮的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)...); \
    }
定义提升(f)\ []无异常(无异常(f(std::forward(xs)…))\ ->decltype(f(std::forward(xs)…)\ { \ 返回f(std::forward(xs)…)\ }
首先,一个固定类型的具体示例

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)... ) ); }
};
所以我们可以

using foo_t = OVERLOAD_SET_TYPE(foo);

不能将函数的重载集作为对象进行操作;唯一的方法就是通过文本。因此是宏观的


这具有完美转发的所有常见缺陷。通常无法避免这些缺陷。

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

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)... ) ); }
};
所以我们可以

using foo_t = OVERLOAD_SET_TYPE(foo);

不能将函数的重载集作为对象进行操作;唯一的方法就是通过文本。因此是宏观的


这具有完美转发的所有常见缺陷。一般来说,没有办法避免这些缺陷。

这样做的动机是什么?您是否发现
std::function
不起作用的用例?@RSahu:std::functions没有数据成员吗?如果您不需要它的所有功能,为什么要使用
std::function
?除非您需要类型擦除和所有权语义,否则它不是正确的作业工具。@einpoklum,确实如此@所以我不能用它。我需要一个没有数据成员的类型。这样做的动机是什么?您是否发现
std::function
不起作用的用例?@RSahu:std::functions没有数据成员吗?如果您不需要它的所有功能,为什么要使用
std::function
?除非您需要类型擦除和所有权语义,否则它不是正确的作业工具。@einpoklum,确实如此@所以我不能用它。我需要一个没有数据成员的类型。您的构造如何区分
a
的重载?@einpoklum:除非您明确指定您感兴趣的重载,否则它无法区分。在我文章的第二部分,我展示了一些解决这个问题的建议。不幸的是,你今天必须使用宏(或拼出lambda)。你的意思是“拼出它的类型”?昆汀:我表达得很糟糕-编辑后清楚吗?@einpoklum没有提到CUDA要求是一件很难忽略的事情。你在你的问题中明确要求。不要移动球门柱;如果您对在纯C++11 CUDA兼容代码中解决此问题有疑问,请提出另一个问题。您的构造如何区分
a
的重载?@einpoklum:除非您明确指定您感兴趣的重载,否则它无法区分。在我文章的第二部分,我展示了一些解决这个问题的建议。不幸的是,你今天必须使用宏(或拼出lambda)。你的意思是“拼出它的类型”?昆汀:我表达得很糟糕-编辑后清楚吗?@einpoklum没有提到CUDA要求是一件很难忽略的事情。你在你的问题中明确要求。不要移动球门柱;如果您对使用纯C++11 CUDA兼容代码解决此问题有疑问,请询问其他问题。