对于普通对象或者函数而言,声明和实现可以分离到*.h和*.cpp(比如说这里写做CommonClass.h和CommomClass.cpp)中去,其中CommonClass.cpp会includeCommonClass.h,因为编译器会根据CommonClass.cpp生成对应CommonClass.obj,由于编译器可以预期类的行为,因此obj文件中会包含实现体对应的二进制代码。如果现有main.cpp使用了该类生成的对象,那么链接器可以在CommonClass.obj找到实现体对应的二进制代码。可是对于模板来说,并不是这样,先看下面这段话。
《C++编程思想》第15章(第300页)说明了原因:
模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。
上面这段话的意思就是说,只有模板实例化时,编译器才会得知T实参是什么。编译器在处理模板实例化时,不仅仅要看到模板的定义式,还需要模版的实现体。
比如说存在模板CTest, 其类定义式写在CTest.h,类的实现体写在CTest.cpp中。对于模板来说,编译器在处理CTest.cpp文件时,编译器无法预知T的实参是什么,所以编译器对其实现是不作处理的(即CTest.obj中没有为编译器为实现体生成的对应的二进制代码)。
现在有main.cpp真正使用了该模板(比方说,生成模板类的一个对象,并调用其函数),如果定义和实现分离,则编译器可以根据定义式生成模板类的对象(因为此处仅仅需要定义式就知道该对象在内存中需要多少空间并进一步分配了),但是调用对象的函数(即真正使用)需要该函数的定义,由于main.cpp仅仅include了模板的声明(所以只能找到该函数的声明),所以无法找到该函数的定义,此时编译器会寄希望于链接器在其他obj文件(这里就是指CTest.obj文件)中寻找该模板的实现体,但是就像之前说过的,CTest.obj中也没有实现体生成的二进制代码。如果定义和实现是在同一个文件(比如说CTest.h)中,那么编译器在编译时就可以寻找到模板的实现体。这里看下面的三个例子。
例1(定义与实现分离,错误示范)
// CTest.
Boost.Asio 初探
简而言之,通过利用Boost.Asio,I/O对象可以执行异步/同步的操作。在使用Asio之前,先介绍Asio的工作原理。分为两种情况,同步和异步。
同步
同步情况下,当socket执行一个连接(connect)操作时,工作原理如下图:
如图中所示,你的程序需要一个I/O对象(如socket),一个io_service
对象,io_service
对象可以理解为调度器,其主要作用是将程序和操作系统的I/O服务相连。
// 通过asio库,新建io_service对象
boost::asio::io_service io_service;
// 利用io_service对象构造I/O对象,比如TCP套接字
boost::asio::ip::tcp::socket socket(io_service);
当一个异步连接操作发生时,会有如下事件发生:
1. 调用I/O对象,进行连接操作的初始化
\\ 初始化连接操作,即指出所监听的端口
socket.connect(server_endpoint);
- I/O对象将请求转发给
io_service
对象 io_service
对象调用系统的I/O服务进行连接操作- 操作系统将操作结果返回给
io_service
对象 io_service
将操作结果中的任何错误传入一个boost::system::error_code
类型的对象中去。error_code
可以与特定值进行比较,或者作为布尔值进行判断(比如,false表示没有发生错误)。接着,io_service
将结果转发回I/O对象。- 如果操作失败,则
io_service
将跑出类型为boost::system::system_error
的异常。如果代码如下:
boost::system::error_code ec;
socket.connect(server_endpoint, ec);
则不会有异常抛出,取而代之的是,将error_code
变量的值传入ec中返回。
异步
异步的工作原理与同步不一样,如下图:
事件发生顺序如下:
1. 调用I/O对象,进行连接的初始化
socket.async_conne
0x00 环境
- 系统:ubuntu14.04或者ubuntu16.04
- vim --version查看是否支持python2或者3,并且vim版本大于等于7.4.143
0x01 安装YCM
一般有两种安装方式,推荐使用第一种
通过Vundle安装YCM
安装 Vundle插件
git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim
在vim的配置文件 ~/.vimrc添加插件
call vundle#begin()
" 其他插件
Plugin 'Valloric/YouCompleteMe’
" 其他插件
call vundle#end()
配置完.vimrc保存,并运行:PluginInstall安装插件,该插件安装时间较长,须耐心等待
通过git安装YCM
下载 (在 ~/.vim/bundle
目录下)
$ git clone --recursive https://github.com/Valloric/YouCompleteMe.git
检查完整性(在 ~/.vim/bundle/YouCompleteMe
目录下)
$ git submodule update --init --recursive
0x02 下载最新版的libclang的预编译二进制文件
如果不需要C系语言的语义补全,则跳过0x02,否则继续
下载libclang的预编译二进制文件(version >= 3.9)
找个地方存放,比如我将解压之后的文件存放在~/download/ycm_tmp_clang_llvm/
目录下,其下有bin,include,lib,libexec,share文件夹。
0x03 编译安装ycm_core库
安装编译YCM core库所需要的依赖
# python的开发包
sudo
LLVM简介
LLVM是伊利诺伊大学的一个开源项目,LLVM提供了完整的C/C++工具链,Clang属于其中的一个子项目,是 LLVM 原生的 " C/C++/Objective-C"编译器前端,Clang负责完成词法和语法分析,而代码优化和机器代码的生成工作由LLVM后端完成。vim中的插件YouCompleteMe就是利用Clang完成语法分析并给出精确的自动补全和语法错误提示(即静态分析)。
安装
简单来说,Clang 和 CompileRT 这两个子项目为 LLVM 提供了 C, C++, Objective C 和 Objective C++ 的前端及动态库支持,使得我们可以使用 Clang 来编译和构建项目。而要构建Clang,必须先构建LLVM核心库。
可从远程库http://llvm.org/svn/llvm-project/llvm/tags/中找到
比如我使用http://llvm.org/svn/llvm-project/llvm/tags/RELEASE_500/final/
安装必要的包
sudo apt-get install subversion
sudo apt-get install cmake
建立目录,统一存放
cd ~/download/
sudo mkdir llvm-install
cd llvm-install
- llvm core放在llvm-install目录下
- clang 放在 llvm目录下的tools目录下
- compileRT放在llvm目录下的projects目录下
组织结构如下:
llvm/
/tools/clang
/projects/compiler-rt
下载 llvm core库
svn co http://llvm.org/svn/llvm-project/llvm/tags/RELEASE_500/final llvm
下载clang:
cd llvm/tools
svn co http:/