网站开发必须要搭建环境吗,广 做网站蓝光电影下载,wordpress 微博 主题,网站佣金怎么做凭证问题背景 在下面的代码中#xff0c;Input输入器 输入数据#xff0c;希望A和B 接收数据。但使用的赋值#xff0c;导致in.a和a只是拷贝数据#xff0c;而不是同一个对象#xff0c;使得数据不同步。 #include iostream
struct A
{int age 32;
};
struct B
{int …问题背景 在下面的代码中Input输入器 输入数据希望A和B 接收数据。但使用的赋值导致in.a和a只是拷贝数据而不是同一个对象使得数据不同步。 #include iostream
struct A
{int age 32;
};
struct B
{int age 10;
};struct Input
{void fun(int i){a.age i;b.age i;}A a;B b;
};
int main(int argc, char *argv[])
{Input in;A a;B b;in.a a;in.b b;in.fun(3);std::couta.age b.agestd::endl;//32 10return 0;
}解决方法1如下所示当希望修改in.a的age时能修改到A a的age需要传指针A而且还要手动指定in.a a #include iostream
struct A
{int age 32;
};
struct Input
{void fun(int i){a-age i;std::couta-agestd::endl;}A* a;
};
int main(int argc, char *argv[])
{Input in;A a;in.a a;in.fun(4);//4return 0;
}解决方法2使用function实现回调函数将fun函数的赋值操作写在回调函数中 #include iostream
#includefunctional
struct A
{int age 32;
};
struct Input
{void fun(int i){callback(i);}std::functionvoid(int) callback;
};
int main(int argc, char *argv[])
{Input in;A a;in.callback [a](int i){a.age i;std::couta.agestd::endl;};in.fun(4);//4return 0;
}方法3将添加回调函数和执行回调函数抽离出来实现成Signal信号的形式 #include iostream
#includefunctional
#include vector
struct Signal
{std::vectorstd::functionvoid(int) m_callbacks;void connect(std::functionvoid(int i) callback){m_callbacks.push_back(std::move(callback));}void emit(int i){for(auto callback: m_callbacks){callback(i);}}
};
struct A
{int age 32;
};
struct Input
{void fun(int i){on_input.emit(i);}Signal on_input;
};
int main(int argc, char *argv[])
{Input in;A a;in.on_input.connect([a](int i){a.age i;std::couta.agestd::endl;});in.on_input.connect([a](int i){a.age i;std::couta.agestd::endl;});in.fun(4);//4return 0;
}4如果类A需要注册一个退出事件on_exit有如下实现。但实际上我们并不希望在此信号传递参数int i。 #include iostream
#include functional
#include vector
struct Signal
{std::vectorstd::functionvoid(int) m_callbacks;void connect(std::functionvoid(int i) callback){m_callbacks.push_back(std::move(callback));}void emit(int i){for(auto callback: m_callbacks){callback(i);}}
};
struct A
{ void on_input(int i) const {std::coutinput agestd::endl;}void on_exit() const {std::coutexit std::endl;}int age 32;
};
struct Input
{//调用该函数就发出 进入事件和退出事件的信号void fun(int i){on_input.emit(i);on_exit.emit(i);}Signal on_input;//进入事件Signal on_exit;//退出事件
};
int main(int argc, char *argv[])
{Input in;A a;in.on_input.connect([a](int i){a.age i;a.on_input(i);});in.on_exit.connect([a](int i){a.on_exit();});in.fun(4);//4return 0;
}5为了信号更加通用使用变长模板参数来实现。注意…在左边表示定义在右边表示使用 #include iostream
#include functional
#include vector
templateclass ...T//定义T
struct Signal
{std::vectorstd::functionvoid(T...) m_callbacks;//使用Tvoid connect(std::functionvoid(T...) callback){m_callbacks.push_back(std::move(callback));}void emit(T... t){//使用T 定义tfor(auto callback: m_callbacks){callback(t...);//使用t}}
};
struct A
{ void on_input(int i) const {std::coutinput agestd::endl;}void on_exit() const {std::coutexit std::endl;}int age 32;
};
struct Input
{//调用该函数就发出 进入事件和退出事件的信号void fun(int i){on_input.emit(i);on_exit.emit();}Signalint on_input;//进入事件Signal on_exit;//退出事件
};
int main(int argc, char *argv[])
{Input in;A a;in.on_input.connect([a](int i){a.age i;a.on_input(i);});in.on_exit.connect([a](){a.on_exit();});in.fun(4);//4return 0;
}6上述代码main函数中connect时传入的lambda表达式下面在Signal中将其封装为bind方法并提供对应的connect函数使其更类似于Qt信号的connect。实际上Qt中是使用字符串来查找匹配的类型名而这里我们使用模板更加高效 #include iostream
#include functional
#include vectortemplateclass Self, class MemFn
auto bind(Self *self, MemFn memfn){//第2个参数为成员函数指针void(A::*)(int i)这里使用模板来避免写成该复杂类型//调用成员函数指针(a-*memfn)()。如果是普通函数指针就是(*memfn)()这样调用return [self, memfn](auto... t){(self-*memfn)(t...);};
}templateclass ...T//定义T
struct Signal
{std::vectorstd::functionvoid(T...) m_callbacks;//使用Tvoid connect(std::functionvoid(T...) callback){m_callbacks.push_back(std::move(callback));}//提供一个bind版本的connect类似qt语法templateclass Self, class MemFnvoid connect(Self *self, MemFn memfn){m_callbacks.push_back(bind(self, memfn));}void emit(T... t){//使用T 定义tfor(auto callback: m_callbacks){callback(t...);//使用t}}
};
struct A
{ void on_input(int i){age i;std::coutinput agestd::endl;}void on_exit(std::string s) const {std::coutexit sstd::endl;}int age 32;
};
struct Input
{//调用该函数就发出 进入事件和退出事件的信号void fun(int i){on_input.emit(i);on_exit.emit(byebye);}Signalint on_input;//进入事件Signalstd::string on_exit;//退出事件
};int main(int argc, char *argv[])
{Input in;A a;in.on_input.connect(a, A::on_input);in.on_exit.connect(a, A::on_exit);in.fun(4);//4return 0;
}下面写了重载函数test_fun作为要connect的函数此时必须写明要使用哪个函数因此下面使用static_cast进行转换 void test_fun(int m){std::coutint mstd::endl;
}
void test_fun(std::string m){std::coutstring mstd::endl;
}
//function要求必须有唯一的重载这样必须指定使用哪个
in.on_input.connect(static_castvoid(*)(int)(test_fun));7为了避免connect的对象提前析构下面代码使用智能指针 templateclass Self, class MemFn
auto bind(Self self, MemFn memfn){return [self, memfn](auto... t){((*self).*memfn)(t...);};
}void test2(Input input){auto a std::make_sharedA();//使用智能指针而不是A a避免对象提前析构input.on_input.connect(a, A::on_input);//这里智能指针a发生拷贝input.on_exit.connect(a, A::on_exit);
}int main(int argc, char *argv[])
{Input in;test2(in);in.fun(3);return 0;
}如果是connect lambda表达式注意按值捕获否则智能指针和a对象都会提前析构掉 void test2(Input input){auto a std::make_sharedA();input.on_input.connect([a](int i){//注意按值捕获areturn a-on_input(i);});
}