C++ 如何从任意函数中生成函子?
我有一堆函数,我想用作函子(也就是说,使用类型而不是传递指向函数的指针或任何其他类型的数据) 使用标准库或标准库+Boost是否有一种优雅的/惯用的/标准的方法来实现这一点?也许以某种方式使用了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(标准::转发(参数)…);
bind()
或者我应该选择一些简单化的东西(嗯,有点简单化),比如:
模板
结构函子{
使用函数类型=函数;
使用参数\u作为\u tuple\u type=std::tuple;
自动运算符()(参数和…参数)->
decltype(F(标准::转发(参数)…)
{
返回F(标准::转发(参数)…);
}
};
注意事项:
- C++11解决方案是首选,但如果您有一些甚至需要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兼容代码解决此问题有疑问,请询问其他问题。