在实际的boost signal中ƈ没有直接的存?/span>slotQ?/span>boost signal库中有个slotc)Q而是存储?/span>functionQ?/span>boost functioncȝ对象Q对象。而且Z方便控制signal?/span>function之间的联p,引入?/span>connectionc,用来表示signal?/span>function之间的联pR?/span>Connection的对象当然和一?/span>function攑֜了一赗这?/span>boost signal提供了一?/span>connection_slot_paircL存储一?/span>function?/span>connection寏V这样在boost signal中一?/span>slotl的实际定义如下std::list< connection_slot_pair >。ƈ且被重定义ؓ(f)group_listcdQ?/span>typedef std::list<connection_slot_pair> group_listQ。相应的?/span>boost signal?/span>map的实际定义如?/span>std::map<stored_group, group_list, compare_type>Qƈ且被重定义ؓ(f)slot_container_typeQ?/span>typedef std::map<stored_group, group_list, compare_type> slot_container_typeQ。将以上的这些东西组l到一个类中,以便于管理。这个类是named_slot_map?/span>Signal中真正用来管?/span>slot的管理器?/span>
Named_slot_map的类数据成员如下定义Q?/span>boost源码中的一部分Q数据成员部分)
class BOOST_SIGNALS_DECL named_slot_map
{
public:
typedef named_slot_map_iterator iterator;//named_slot_map容器的P代器
private:
typedef std::list<connection_slot_pair> group_list;//function connection对组cd
typedef std::map<stored_group, group_list, compare_type> slot_container_type;//容器cd
typedef slot_container_type::iterator group_iterator;//容器q代器类?/span>
typedef slot_container_type::const_iterator const_group_iterator;
slot_container_type groups;//定义一个用来管?/span>function connectionl的容器对象
group_iterator back;//容器的P代器对象
};
Named_slot_map也是一个容器?/span>Stl的容器ؓ(f)了外界方便访问容器内数据单元Q提供了q代器?/span>Named_slot_map也有自己的P代器。这个P代器是named_slot_map_iteratorcR?/span>Named_slot_map提供了以下方法来获得q代?/span>iterator begin()Q?/span>iterator end()?/span>BeginҎ(gu)提供首P代器Q?/span>endҎ(gu)提供P代器。向容器中插入数据用insert。清除某个数据用而而然eraseQ清I容器中的所有数据用clear?/span>
个h觉得在slot<>中的最有用处的函数?br>void slot_base::create_connection()
{
basic_connection* con = new basic_connection();
{
con->signal = static_cast<void*>(this);
con->signal_data = 0;
con->blocked_ = false ;
con->signal_disconnect = &bound_object_destructed;
}
data->watch_bound_objects.reset(con);
scoped_connection safe_connection(data->watch_bound_objects);
for(std::vector<const trackable*>::iterator i = data->bound_objects.begin();
i != data->bound_objects.end(); ++i)
{
BOOST_SIGNALS_NAMESPACE::detail::bound_object binding;
(*i)->signal_connected(data->watch_bound_objects, binding);
BOOST_SIGNALS_NAMESPACE::detail::auto_disconnect_bound_object disconnector(binding);
con->bound_objects.push_back(binding);
disconnector.release();
}
safe_connection.release();
data->watch_bound_objects.set_controlling(true);
}
2Qstatic对象存储在E序的静态存储区中,而不是在堆栈中。这个对象只在汉书第一ơ调用是初始化,其后不用再初始化?/p>
3Q对于静态对象的初始化,零赋值只寚w定义对象有效Q用戯定义的类型必ȝ构造函数初始化?/p>
4Q静态对象的析构函数在程序的main()函数退出时Q或者标准c函数exit()调用时才被调用。在析构函数中调用exit()是很危险的,因ؓ(f)q样可能引vd@环?/p>
5Q静态对象的销毁是按它们初始化的相反顺序进行的。全局对象L在main()执行之前被创建。如果一个包含静态对象的函数从没有被调用q,那么q个对象的构造函数就没有被执行,所以也׃?x)调用析构函?/p>
6Q一个被明确声明为static的对象或函数的名字对~译单元来说是局部变量,q些名字有内部连接。类声明和局部变量没有联接?/p>
7Qextern表示该名字对所有的~译单元是可见的Q用static和extern限定的对象Lȝ在静态数据区
8Q普通函数是外部q接?/p>
9Q类的静态成员拥有一块单独的存储?而不我们创Z多少个该cȝ对象Q这׃ؓ(f)q些了创Z一个通信的方法?/p>
10Q静态成员的定义必须出现在外部,而且只能有一?/p>
11Q一个类的静态常量可以被用作一个编译时帔R
12Q在局部类(在函数内部定义的c)中不能有静态数据成员?/p>
13Q静态成元函敎ͼ(x)
Q?Q,静态成元函Cؓ(f)该类的全体服务,而不是ؓ(f)cȝ部分对象服务Q?br>Q?Q?静态成员函C能访问一般的数据成员Q只能访问静态数据成员,q且只能调用静态成元函数?/p>
14Qؓ(f)什么静态成元函C能访问一般的数据成员Q也不能调用普通的成员函数?
׃当前对象的地址是被隐藏的传递给被调用的函数的,׃静态成员函C是某个对象独有的Q所以没有this指针Q所以无法调用调用普通成员函敎ͼ同样Ҏ(gu)通成员变量的讉K也用Cthis指针?br>
~译单元
l过预处理之后的文gQ这个是内存中的临时文gQ?br>#include在预处理时被展开Q宏也一?/p>
一个经q展开后的.cpp文g是一个编译单?/p>
一个xx.hQ经q预处理Q?+ 一个xx.cpp = 一个编译单?br>一个编译单元(l过~译Q? xx.obj
整个E序的多?obj加v?l过链接) = .exeQ可执行文gQ?
预处?br>-----------
把一些带#L(fng)Q比方说宏定义,预处理命令(#includeQ等
内部q接与外部连?br>在说内部q接与外部连接前Q先说明一些概c?
1.声明
一个声明将一个名U引入一个作用域;
在c++中,在一个作用域中重复一个声明是合法?
以下都是声明Q?
int foo(int,int); //函数前置声明
typedef int Int; //typedef 声明
class bar; //cd|声?
extern int g_var; //外部引用声明
class bar; //cd|声?
typedef int Int; //typedef 声明
extern int g_var; //外部引用声明
friend test; //友员声明
using std::cout; //名字I间引用声明
friend test; //友员声明
using std::cout; //名字I间引用声明
int foo(int,int); //函数前置声明
在同一个作用域中你可以多次重复q些声明?
有两U声明不能重复,那就是类成员函数?qing)静态数据成员的声明
class foo
{
static int i;
static int i;//不可?
public:
int foo();
int foo();//不可?
};
2.定义
一个定义提供一个实?cd、实例、函?在一个作用域的唯一描述?/p>
在同一作用域中不可重复定义一个实体?/p>
以下都是定义?/p>
int y;
class foo ;
struct bar ;
foo* p;
static int i;
enum Color;
const double PI = 3.1415;
union Rep;
void test(int p) {};
foo a;
bar b;
3.~译单元
当一个c或cpp文g在编译时Q预处理器首先递归包含头文Ӟ形成一个含有所有必要信息的单个源文?q个源文件就是一个编译单元。这个编译单元会(x)被编译成Z个与cpp文g名同名的目标文g(.o或是.obj)。连接程序把不同~译单元中生的W号联系hQ构成一个可执行E序?/p>
4.自由函数
如果一个函数是自由函数Q那么这个函C是类的成员函敎ͼ也不是友元函数?/p>
下面来看内部q接和外部连?/p>
内部q接Q如果一个名U对于它的编译单元来说是局部的Qƈ且在q接时不?x)与其它~译单元中的同样的名U相冲突Q那么这个名U有内部q接(注:(x)有时也将声明看作是无q接的,q里我们l一看成是内部连接的)?/p>
以下情况有内部连?
a)所有的声明
b)名字I间(包括全局名字I间)中的静态自由函数、静态友元函数、静态变量的定义
c)enum定义
d)inline函数定义(包括自由函数和非自由函数)
e)cȝ定义
f)名字I间中const帔R定义
g)union的定?/p>
外部q接:在一个多文gE序中,如果一个名U在q接时可以和其它~译单元交互Q那么这个名U就有外部连接?/p>
以下情况有外部连?
a)c非inline函数L外部q接。包括类成员函数和类静态成员函?/p>
b)c静态成员变量L外部q接?/p>
c)名字I间(包括全局名字I间)中非静态自由函数、非静态友元函数及(qing)非静态变?/p>
下面举例说明Q?/p>
a)声明、enum定义、union定义有内部连?/p>
所有的声明、enum定义?qing)union定义在编译后不会(x)产生q接W号Q也是在不同编译单元中有相同名U的声明?qing)enum、union定义q不?x)在q接时发生发现多个符L(fng)错误?/p>
// main.cpp
typedef int Int; //typedef 声明Q内部连?/p>
enum Color; //enum定义,内部q接
union X //union定义Q内部连?br>{
long a;
char b[10];
};
int main(void)
{
Int i = red;
return i;
}
// a.cpp
typedef int Int; //在a.cpp中重声明一个intcd别名Q在q接时不?x)发生错?br>enum Color; //在a.cpp中重定义了一个enum ColorQ在q接时不?x)发生错?br>const Int i =blue; //const帔R定义Q内部连?br>union X //union定义Q内部连?br>{
long a;
char b[10];
};
b)名字I间中静态自由函数、静态友元函数、静态变量、const帔R定义有内部连?/p>
// main.cpp
namespace test
{
int foo(); //函数声明Q内部连?br> static int i = 0; //名字I间静态变量定义,内部q接
static int foo() { return 0;} //名字I间静态函数定义,内部q接
}
static int i = 0; //全局静态变量定义,内部q接
static int foo() {return 1;} //全局静态函数定义,内部q接
const int k = 0; //全局const帔R定义Q内部连?br>int main(void)
{
return 0;
}
//a.cpp
namespace test
{
int i = 0; //名字I间变量定义Q外部连?br> int foo() {return 0;} //名字I间函数定义Q外部连?br>}
int i = 0; //全局变量定义Q外部连?br>int k = 0; //全局变量定义Q外部连?br>int foo() { return 2;} //全局函数定义Q外部连?
在全局名字I间中,main.cpp中定义了静态变量i,帔Rk,?qing)静态自由函数foo{,q些都有内部q接。如果你这些变量或函数的static或是const修饰W去掉,在连接时׃(x)现multiply defined symbols错误Q它们与a.cpp中的全局变量、全局函数发生冲突?/p>
c)cd义L内部q接,而非inlinecL员函数定义L外部q接Q不个成员函数是静态、虚拟还是一般成员函敎ͼc静态数据成员定义L外部q接?
1.cȝ定义有内部连接。如果不是,惌一下你?个cpp文g中include定义了类Base的头文gQ在4个编译单元中的类Base都有外部q接Q在q接的时候就?x)出错?/p>
看下面的例子:
//main.cpp
class B //cd义,内部q接
{
static int s_i; //静态类成员声明Q内部连?
public:
void foo() { ++s_i;} //cinline函数Q内部连?br>};
struct D
{
void foo(); //cL员函数声明,内部q接
};
int B::s_i = 0; //c静态数据成员定义,外部q接
void D::foo() //cL员函数定义,外部q接
{
cout << "D::foo in main.cpp" <
}
int main() //main函数Q全局自由函数Q外部连?br>{
B b;
D d;
return 0;
}
//a.cpp
class B
{
int k;
};
struct D
{
int d;
};
在这个例子中Qmain.cpp与a.cpp中都有class B和class D的定义,但在~译q两个cpp文g时ƈ不发生link错误?/p>
2.cȝ非inline成员函数(一般,静态,虚拟都是)L外部q接Q这样当你include了某个类的头文gQ用这个类的函数时Q就能连接到正确的类成员函数上,l箋以上面ؓ(f)例子Q如果把a.cpp中的struct D改ؓ(f)
struct D //cd?br>{
int d;
void foo(); //cL员函数声?br>};
void D::foo() //cL员函数定义,外部q接
{
cout << " D::foo in a.cpp" <
}
q时main.cpp与a.cpp中的D::foo都有外部q接Q在q接׃(x)出现multiply defined symbols错?
3.cȝ静态数据成员有外部q接Q如上例的B::s_i,q样当你在main.cpp中定义了c静态数据成员,其它~译单元若用了B::s_i,׃(x)q接到main.cpp对应~译单元的s_i?/p>
d)inline函数L内部q接Q不个函数是什么函?/p>
// main.cpp
inline int foo() { return 1;} //inline全局函数Q内部连?br>class Bar //cd义,内部q接
{
public:
static int f() { return 2;} //inline c静态函敎ͼ内部q接
int g(int i) { return i;} //inline cL员函敎ͼ内部q接
};
class Base
{
public:
inline int k()Q?//cL员函数声明,内部q接
}Q?/p>
inline int Base::k(){return 5;} //inline cL员函敎ͼ内部q接
int main(void)
{
return 0;
}
如果你的BasecL定义在Base.h中,而Base的inline 函数是在Base.cpp中定义的Q那么在main.cpp中include "Base.h"~译不会(x)出现问题Q但在连接时?x)找不到函数kQ所以类的inline函数最好放到头文g中,让每一个包含头文g的cpp都能扑ֈ inline函数?/p>
现在对c++中的q接有了一个认识,能清楚的知道是什么原因生连接时错误。当你在q接时生连接不到的错误Q这说明所有的~译单元都没有这个实体的外部q接Q当你在q接时发现有多个q接实体Q这说明有多个编译单元提供了同名的有外部q接的实体。同Ӟ在进行程序设计时Q也要注意不要只有本编译单元用到的函数、类、变量等有外部连接,减少与其它编译单元的q接冲突?/p>
不过在这里没有说明template函数?qing)template class的连接性,q且对一些特别的情况也没有作?比如inline函数不能被inline)?br>
'.h'?.hpp'里的代码?x)?include宏添加到'.c'?.cpp'文g中?br>q个q程发生在预~译期,预编译器Q现在好像没有这个东西了Q都
在编译器中完成)完成q䆾工作?/p>
一?.c'?.cpp'是一个编译单元。编译器其译成二q制代码?/p>
An non-nullary metafunction is invoked by instantiating the class template with particular template parameters (metafunction arguments);
一个非无参的原操作被一个有详细模板参数的模板类hQ?br>the result of the metafunction application is accessible through the instantiation's nested type typedef.
原操作应用的q回值是一个通过模板cd例可取的内嵌的类型定义?/p>
All metafunction's arguments must be types (i.e. only type template parameters are allowed).
所有的原操作的参数必须是类型?/p>
A metafunction can have a variable number of parameters.
一个原操作能有一个数量变化的参数
A nullary metafunction is represented as a (template) class with a nested type typename member.
一个无参数原操作被表现为有内嵌重命名类型的c?/p>
原操作的三种表达式(f是一个原操作Q?br>1 f::type
2 f<>::type
3 f< a1,..,an >::type
Lambda Expression 构造和分配表达?/p>
A Lambda Expression is a compile-time invocable entity in either of the following two forms:
一个构造和分配表达式是下面两个中的一个编译期调用单元
Metafunction Class
原操作类
Placeholder Expression
站位W表辑ּ
Most of the MPL components accept either of those, and the concept gives us a consice way to describe these requirements.
大部分的MPLlg接收它们其中一个,