传递非泛型函数的最有效方法是什么?
What is the most efficient way to pass a non generic function?
我正在学习C++函数式编程。我的目的是传递一个非泛型函数作为参数。我知道模板方法,但是我想限制函数签名作为 API 设计的一部分。我在 cpp.sh 上制定了 4 种不同的方法示例:
// Example program
#include <iostream>
#include <string>
#include <functional>
typedef int(functor_type)(int);
int by_forwarding(functor_type &&x) {
return x(1);
}
int functor_by_value(functor_type x) {
return x(1);
}
int std_func_by_value(std::function<functor_type> x) {
return x(1);
}
int std_func_by_forwarding(std::function<functor_type> &&x) {
return x(1);
}
int main()
{
std::cout << functor_by_value([](int a){return a;}); // works
std::cout << std_func_by_value([](int a){return a;}); // works
std::cout << std_func_by_forwarding(std::move([](int a){return a;})); // works
//std::cout << by_forwarding([](int a){return a;}); // how to move lambda with forwarding ?
}
上述任何尝试是否正确?如果没有,我该如何实现我的目标?
(基于评论的澄清(
可以使用std::is_invocable
来限制签名:
template<typename x_Action> auto
functor_by_value(x_Action && action)
{
static_assert(std::is_invocable_r_v<int, x_Action, int>);
return action(1);
}
在线编译器
其他替代方案:
template <typename Func>
auto functor_by_value(Func&& f)
-> decltype(std::forward<Func>(f)(1))
{
return std::forward<Func>(f)(1);
}
我想将函数签名限制为 API 设计的一部分。
所以限制它:
#include <functional>
#include <type_traits>
#include <iostream>
/// @tparam F is a type which is callable, accepting an int and returning an int
template
<
class F,
std::enable_if_t
<
std::is_convertible_v<F, std::function<int(int)>>
>* = nullptr
>
int myfunc(F &&x) {
return x(1);
}
int main()
{
auto a = myfunc([](int x) { std::cout << x << std::endl; return 1; });
// does not compile
// auto b = myfunc([]() { std::cout << "foo" << std::endl; return 1; });
}
像往常一样,这取决于你的编译器今天有多好,以及将来有多好。
目前,编译器不太擅长优化std::function
。令人惊讶的是,std::function
是一个复杂的对象,有时必须分配内存来维护有状态的 lambda 函数。它还使std::function
必须能够以透明的方式引用成员函数、常规函数和 lambda 的问题复杂化。这种透明度具有高昂的运行时成本。
因此,如果您想要最快的代码,则应小心std::function
.出于这个原因,第一个变体是最快的(在今天的编译器上(:
int functor_by_value(functor_type x) {
return x(1);
}
它只是传递一个指向函数的指针。
当涉及有状态 lambda 时,您只有两种选择。要么将 lambda 作为模板参数传递,要么转换为std::function
。因此,如果你想要使用 lambda 的最快代码(在今天的编译器中(,你可以将函数作为模板化参数传递。
由于 lambda 函数可能具有大状态,因此传递它可能会复制大状态(当无法复制省略时(。GCC 将直接在参数列表中构造 lambda(没有副本(,但嵌套函数将调用 lambda 的复制构造函数。为避免这种情况,请通过 const 引用(在这种情况下它不能可变(或通过右值引用传递它:
template<class Func>
void run2(const Func & f)
{
std::cout << "Runningn";
f();
}
template<class Func>
void run(const Func & f)
{
run2(f);
}
int main()
{
run([s=BigState()]() { std::cout << "applyn"; });
return 0;
}
或:
template<class Func>
void run2(Func && f)
{
f();
}
template<class Func>
void run(Func && f)
{
run2(std::forward<Func>(f));
}
int main()
{
run([s=BigState()]() { std::cout << "applyn"; });
return 0;
}
如果不使用引用,BigState(( 将在复制 lambda 时被复制。
更新:再次阅读问题后,我看到它想要限制签名
template<typename Func,
typename = std::enable_if_t<
std::is_convertible_v<decltype(Func(1)), int>>>
void run2(const Func & f)
{
std::cout << "Runningn";
f();
}
这会将其限制为可以接受int
的任何函数(可能带有隐式强制转换(,并返回隐式转换为int
的int
或任何类型。但是,如果您只想接受完全接受int
并返回完全 int 的类似函数的对象,您可以查看 lambda 是否可以转换为std::function<int(int)>
- 在C++中初始化向量映射的最有效方法
- 将此布尔值传递给此函数的最有效方法是什么?
- 比较C++变量的最有效方法
- 在 c++ 中解决段树以外的范围查询的有效方法是什么?
- 存储变量的更有效方法是什么?
- 确保套装新鲜度的有效方法
- 当映射包含字符串向量作为值时,从值中获取键的有效方法
- 映射唯一值和重复值的有效方法.可以访问键或值的位置
- 在C++事务之间存储大量字符数据的有效方法
- 在unordered_multimap中精确迭代一次每个键的有效方法
- 一种将 Dart 中的字节数据转换为 C++ 中的无符号字符*的有效方法?
- 检查两个向量是否并行的最有效方法
- 从浮点数中删除小数部分但保留类型的有效方法
- 传递非泛型函数的最有效方法是什么?
- 按升序打印矢量的所有元素直到它为空而没有重复项的最有效方法是什么?
- 创建字符串数组的有效方法
- 返回一个引用C++中另一个类对象的对象的有效方法
- C++去除前x个元素的有效方法,在不改变向量大小的情况下将第x+1个元素推到第一个
- 将一种数据类型的向量复制到同一数据类型的结构向量中的有效方法是什么
- 从std::map值中获取密钥的有效方法