如何组合lambda,vairadic函数和函数指针?
How to combine lambda, vairadic functions and function pointers?
我有一个好主意,它简化了(对我来说(很多事情。
假设你有一个函数,它接受一个带有 x 参数的函数,如果事件发生,该函数将被执行。为了简化这一点,你用typedef定义了一个新的类型,这是一个函数指针。
typedef void (*HandlerFunction)(...);
void setHandler(HandlerFunction fun) {...}
现在,您可以使用 setHandler 函数来...使用带有其他 sepsific 参数的 lambda 函数设置处理程序,因为您知道将始终使用这些特定参数调用此函数。
setHandler([](int i, std::string arg) {
std::cout << "Event with i=" << i << " and arg=" << arg << "!" << std::endl;
});
现在的问题是...这在C++甚至可能吗,什么时候是,如何?
可变参数
我想通了,如何使用可变参数列表来做到这一点。诀窍是在可更改函数周围使用包装器并使用va_copy
:
#include <iostream>
#include <functional>
#include <cstdarg>
std::function<void (int, va_list)> foo = [] (int numargs, va_list args)
{
va_list args_copy;
va_copy(args_copy, args);
std::cout << "Old Foo " <<va_arg(args_copy,int) << std::endl;
va_end(args_copy);
};
void set_foo(std::function<void (int, va_list)> new_foo)
{
foo = new_foo;
}
void wrapper(int numargs, ...)
{
va_list args;
va_start(args, numargs);
foo(numargs, args);
va_end(args);
}
int main() {
wrapper(123,456);
set_foo([](int numargs, va_list args)
{
va_list args_copy;
va_copy(args_copy, args);
std::cout << "New Foo " << va_arg(args_copy,int) << std::endl;
va_end(args_copy);
});
wrapper(123,456);
return 0;
}
这导致:
Old Foo 456
New Foo 456
我不知道为什么需要包装器,也许有人知道。但它:P有效
已知参数
您可以使用initializer_list
将特定类型的可变参数传递给变量 lambda。
#include <iostream>
#include <functional>
#include <initializer_list>
std::function<void (std::initializer_list<int>)> foo = [](std::initializer_list<int> args)
{
for (auto i: args) std::cout << "Old Foo: "<< i << 'n';
};
void setFoo(std::function<void (std::initializer_list<int>)> new_foo) {
foo = new_foo;
};
int main()
{
foo({2, 4, 5});
std::cout << std::endl;
setFoo([](std::initializer_list<int> args)
{
for (auto i: args) std::cout << "New Foo: "<< i << 'n';
});
foo({2, 4});
}
这将返回:
Old Foo: 2
Old Foo: 4
Old Foo: 5
New Foo: 2
New Foo: 4
在我看来,我已经找到了最好的解决方案。
我使用此类作为函数的容器:
#define C(...) __VA_ARGS__
#define F(a, ...) (std::function<void(__VA_ARGS__)>)[ a ](__VA_ARGS__)
#pragma once
#include <memory>
#include <functional>
class HandlerFunc {
private:
struct function_b {
virtual ~function_b() {};
};
template<typename... Args>
struct func : function_b {
typedef std::function<void(Args...)> func_t;
func_t funct;
func(func_t f) : funct(f) {};
};
std::unique_ptr<function_b> fb;
public:
template <typename... Args>
HandlerFunc(std::function<void(Args...)> f) : fb(new func<Args...>(f)) { };
template <typename... Args>
HandlerFunc& operator=(std::function<void(Args...)> f) {
fb = std::unique_ptr<function_b>(new func<Args...>(f));
return *this;
};
template <typename... Args>
void operator()(Args... args) const {
func<Args...>* f = dynamic_cast<func<Args...>*>(fb.get());
if (f)
f->funct(args...);
else
throw std::runtime_error("Invalid arguments to function object call!");
};
};
现在可以编写这样的代码:
std::vector<HandlerFunc> funcs;
template<typename... Args>
void add(std::function<void(Args...)> func) {
funcs.push_back(func);
}
int main() {
int a = 321;
int b = 123;
add(F(C(a, b), int i){
std::cout << a << b << i << std::endl;
});
add(F(C(=), std::string str){
std::cout << b << a << str << std::endl;
});
int i = 0;
for (auto& func : funcs) {
if (i < 1) func(1234);
else func("meep");
}
}
我唯一想要的一件事,是一个转换这样的东西的 #define
add(F([=], int i, std::string str){
...
});
进入这个
add((std::function<void(int, std::string))[=](int i, std::string str){
...
});
我对预处理器之类的东西很陌生^^
我想象你想做一些看起来像这样的事情:
Delegator delegator;
delegator.set_handler(handler);
不幸的是,在声明Delegator
时,必须知道handler
的类型或其类型签名(带std::function
(。 根据你想做什么,这还不错。 如果库的用户可以一次性定义一堆处理程序,并且您可以向用户枚举处理程序应该处理的类型,例如
//The library user defines this
struct MyHandlers {
void operator()(int){
std::cout << "Event with i=" << i << std::endl;
}
template<class T>
void operator()(std::string str, T t_){
std::cout << "Event with str=" << str << " and some class=" << t_ << "!" << std::endl;
}
void operator()(std::string str){ /** more code **/ }
};
然后,您可以执行类似于您最初想要做的事情。
//This would go in the library
template<class Handlers>
struct Delegator_t {
Handlers handlers;
template<class T>
void do_stuff_which_eventually_calls_handlers(T t_) {
std::string string = "string";
if (/** condition **/) {
handlers(5);
} else {
handlers(string, t_);
}
//The user's third overload never gets called.
}
}
template<class Handlers>
Delegator_t<Handlers> Delegator(Handlers handlers){ return{std::move(handlers)}; }
最后,用户可以通过以下方式使用您的库及其MyHandlers
类
auto delegator = Delegator(MyHandlers{});
SomeClass some_class(/** some args **/);
delegator.do_stuff_which_eventually_calls_handlers(some_class);
当然,如果用户必须在不同的时间点向同一个委托人注册各种处理程序,则上述方法是无用的。
你可以做的一些事情
#include <iostream>
#include <functional>
void exec_handler(std::function<void(int, std::string)> cb) {
static int cnt = 0;
cb(cnt++, "from_exec_handler");
}
void handler1(int count, std::string name) {
std::cout << "handler1t" << count << " " << name << std::endl;
}
void handler2(int count, std::string name, std::string name2) {
std::cout << "handler2t" << count << " " << name << " " << name2 << std::endl;
}
int main(int argc, char *argv[]) {
auto handler_lambda = [](int count, std::string name) {
std::cout << "lambdatt" << count << " " << name << std::endl;
};
auto clojure = [](int count, std::string name) {
return handler2(count, name, "clojure");
};
auto partial = std::bind(handler2, std::placeholders::_1, std::placeholders::_2, "partial");
exec_handler(handler1);
exec_handler(handler_lambda);
exec_handler(clojure);
exec_handler(partial);
}
输出:
handler1 0 from_exec_handler
lambda 1 from_exec_handler
handler2 2 from_exec_handler clojure
handler2 3 from_exec_handler partial
相关文章:
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如何组合lambda,vairadic函数和函数指针?