C++11 迁移器的状态--2013年4月15日(一)

2014-11-24 03:12:36 · 作者: · 浏览: 0

自从2012年12月早些时候,C++11迁移器工具cpp11-migrate的设计文档发布以来,我们的开发工作进展顺利。在这篇文章里,我将介绍一下cpp11-migrate目前已经实现了哪些功能,即将实现哪些功能,以及如何加参与到这个项目里来。

cpp11-migrate的目标是实现一个C++11迁移器,这个迁移器可以实现源码到源码的转换,使用C++11的新特性去迁移已有的C++代码,从而提高这些已有的C++代码的可维护性、可读性、运行性能以及缩短编译性能。开发工作仍然处于早期阶段,目前的转换器主要分为两类。这个迁移器是基于Clang的LibTooling和AST Matching library。

目前所有的开发工作是Intel的一个小核心组在进行。我们目前工作的中心是建立起基础平台和测试,实现一小部分基本的转换器,同时确保这些转换器工作良好。我们的目标是希望可以这个工具对社区是实用的,所以我们总是聆听转换器的想法和反馈。
如何获得cpp11-migrate
cpp11-migrate位于Clang额外工具包。构建cpp11-migrate,你将需要LLVM和Clang的源码。跟随Clang的 Getting Started instructions 指引,确保履行 下载了可选的额外的工具包。一旦下载到了构建 系统对应的目录,重新认证之后,将自动包含Clang额外工具包作为接下来整体构建的一部分。如果你使用的是CMake构建系统,你可以构建 cpp11-migrate通过使用cpp11-migratetarget参数。CMake提供的 check-clang-tools将运行所有Clang额外工具包括cpp11-migrate的回归测试。
目前已经实现的转换器
这个C++11迁移器目前支持C++11的四个特性: 基于范围的for循环为空指针提供了nullptr关键字auto类型说明符override虚拟说明符 基于范围的for循环转换器曾经作为一个单独的叫做loop-convert的工具存在过,它的贡献者是Sam Panzer。当打算开发更多的转换器的时候,实现的思路就变成了把所有的转换器放在一个单独的工具管辖之下,于是 cpp11-migrate诞生了。基于范围的for循环转换器替换了下列三种普遍情况下的任何一种for循环: 使用迭代器遍历容器:
std::vector<int> myVec;
for (std::vector<int>::iterator I = myVec.begin(),
                                E = myVec.end();
     I != E; ++I)
  llvm::outs() << *I;
std::vector<int> myVec;
for (auto & elem : myVec)
  llvm::outs() << elem;
遍历静态数组:
int arr[] = {1,2,3,4,5};
for (int i = 0; i < 5; ++i)
  llvm::outs() << arr[i];
int arr[] = {1,2,3,4,5};
for (auto & elem : arr)
  llvm::outs() << elem;
使用操作符[]或者()遍历类似数组的容器:
std::vector<int> myVec;
for (int i = 0; i < myVec.size(); ++i)
  llvm::outs() << v[i];
std::vector<int> myVec;
for (auto & elem : myVec)
  llvm::outs() << elem;
nullprt转换器使用最新的nullprt关字,当指针被被初始化或者赋值为一个空值的时候。万一这时候还有一个显式的转换存在,这个显示的转换将保留下来,避免引入两意性到代码。
void foo(int *arg);
void foo(float *arg);

int *IntPtr = 0;
float *FloatPtr = NULL;
foo(static_cast<int*>(0));
void foo(int *arg);
void foo(float *arg);

int *IntPtr = nullptr;
float *FloatPtr = nullptr;
foo(static_cast<int*>(nullptr));

auto类型说明符转换器使用新的auto关键字替换了变量声明的类型说明符。一般来说,只要变量声明的类型和它的初始化类型相匹配,这样的替换就可以做。当然,这个转换器只是针对一小部分特殊的方便可读性和可维护性的实用场景: 当变量是一个STL容器的迭代器的时候。
std::vector
  
   int, std::string> >::iterator NameAgeI = People.begin();

   for (std::vector
   
    ::iterator I = Container.begin(), E = Container.end; I != E; ++I) { // ... } 
   
  
auto NameAgeI = People.begin();
for (auto I = Container.begin(),
                                  E = Container.end;
     I != E; ++I) {
  // ...
}
当初始化器是一个使用new操作符的分配空间动作时。
MyType *VarPtr = new MyType();
MyType * const VarCPtr = new MyType();
auto VarPtr = new MyType();
auto const VarCPtr = new MyType();
正在开发支持的第三种情况:使用工厂方法创建对象。
MyType *FooPtr = makeObject
  
   (/*...*/);
MyType *BarPtr = MyType::create(/*...*/);

  
auto FooPtr = makeObject
  
   (/*...*/);

   auto BarPtr = MyType::create(/*...*/);

  
在每一种情形之下,为声明产生的类型都应该是读者来说非常明显的。标准容器的迭代器是通过具有特殊名字的函数所创建的,并且使用在特殊的情景之下。对于工厂方法和new操作符来说,类型已经在初始化的时候表明了,所以在变量声明的时候重复说明没有必要。
override虚拟说明符转换器,Philip Dunstan贡献,它是这个迁移器的第四个转换器并且是第一个来自Intel核心小组之外的贡献。这个转换器检测派生来之中的重载父类成员函数的虚成员函数,并且给它们加上override虚拟说明符。
class Parent {
public:
  virtual int getNumChildren();
};

class Child {
public:
  virtual int getNumChildren();
};
class Parent {
public:
  virtual int getNumChildren();
};

class Child {
public:
  virtual int getNumChildren() override;
};
更多关于这些转换器的细节,包括它们能做什么、不能做什么,怎么样调整它们的行为,甚至了解他们的局限性,这些都可以在这个文档cpp11-migrate User's Manual中找到。

在真实的工程