Status of the C++11 Migrator

Monday, April 15, 2013

Status of the C++11 Migrator

Since the design document for cpp11-migrate, the C++11 migrator tool, was first proposed in early December 2012 development has been making steady progress. In this article I’ll talk about what’s been implemented in cpp11-migrate so far, what’s coming up, and how you can get involved.

The purpose of the C++11 Migrator is to do source-to-source translation to migrate existing C++ code to use C++11 features to enhance maintainability, readability, runtime performance, and compile-time performance. Development is still early and transforms fall mostly into the first two categories. The migrator is based on Clang’s LibTooling and the AST Matching library.

Most of the development so far has been carried out by a small core group at Intel. Our focus so far has been to set up project infrastructure and testing, implement a few basic transforms, and make sure those transforms work well. Our aim is to make this tool useful to the community so we’re always listening for transform ideas and feedback.

How to Get cpp11-migrate

cpp11-migrate is located in the Extra Clang Tools repository. To build cpp11-migrate, you will need the LLVM and Clang sources as well. Follow the directions in Clang’s Getting Started instructionscpp11-migrate.check-clang-tools

The Transforms So Far

The C++11 Migrator currently supports four features of C++11:

  • Range-based for loops
  • The nullptr literal for null pointers
  • The auto type specifier
  • override virtual specifier

The range-based for-loop transform once existed as a stand-alone tool called contributed by Sam Panzer. When development on more transforms started, the idea became to pull all transforms under the jurisdiction of a single tool and was born. The range-based for-loop transform replaces for-loops used in one of the following three common situations:

The range-based for-loop transform once existed as a stand-alone tool called contributed by Sam Panzer. When development on more transforms started, the idea became to pull all transforms under the jurisdiction of a single tool and was born. The range-based for-loop transform replaces for-loops used in one of the following three common situations:

  1. Loops over containers using iterators

  2. std::vector<int> myVec;
    for (std::vector<int>::iterator I = myVec.begin(),
                                    E = myVec.end();
         I != E; ++I)
      llvm::outs() << *I;
    
  3. std::vector<int> myVec;
    for (auto & elem : myVec)
      llvm::outs() << elem;
    
  4. Loops over statically allocated arrays

  5. int arr[] = {1,2,3,4,5};
    for (int i = 0; i < 5; ++i)
      llvm::outs() << arr[i];
    
  6. int arr[] = {1,2,3,4,5};
    for (auto & elem : arr)
      llvm::outs() << elem;
    
  7. Loops over array-like containers using operator[] or at().

  8. std::vector<int> myVec;
    for (int i = 0; i < myVec.size(); ++i)
      llvm::outs() << v[i];
    
  9. std::vector<int> myVec;
    for (auto & elem : myVec)
      llvm::outs() << elem;
    

The nullptr transform uses the new literal where pointers are being initialized with or assigned a null value. In cases where an explicit cast is used, the explicit cast is left behind to avoid introducing ambiguities into the code.

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));

The auto type specifier transform replaces the type specifier for variable declarations with the new keyword. In general, such a replacement can be done whenever the type of the variable declaration matches the type of its initializer. However, the transform targets only a few specific useful situations with readability and maintainability in mind:

  1. When the variable is an iterator for an STL container.

  2. std::vector<std::pair<int, std::string> >::iterator NameAgeI = People.begin();
    for (std::vector<MyType>::iterator I = Container.begin(),
                                       E = Container.end;
         I != E; ++I) {
      // ...
    }
    
  3. auto NameAgeI = People.begin();
    for (auto I = Container.begin(),
                                      E = Container.end;
         I != E; ++I) {
      // ...
    }
    
  4. When the initializer is an allocation using the new operator.

  5. MyType *VarPtr = new MyType();
    MyType * const VarCPtr = new MyType();
    
  6. auto VarPtr = new MyType();
    auto const VarCPtr = new MyType();
    

Support for a third situation is in development: creating objects with factory functions.

MyType *FooPtr = makeObject<MyType>(/*...*/);
MyType *BarPtr = MyType::create(/*...*/);

auto FooPtr = makeObject<MyType>(/*...*/);
auto BarPtr = MyType::create(/*...*/);

In each situation, the deduced type for the declared variable should be obvious to the reader. Iterators for standard containers are created by functions with specific names and are used in specific situations. For factory functions and operator newthe type is spelled out in the initializer so repeating it in the variable declaration is not necessary.

The override virtual specifier transform, contributed by Philip Dunstan, is the migrator’s fourth transform and the first to be contributed from outside the core group at Intel. This transform detects virtual member functions in derived classes that override member functions from parent classes and adds the override virtual specifier to the function.

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;
};

More details on these transforms, what they can and can’t do, how to adjust their behaviour, and known limitations can be found in the .

Testing on Real Projects

What better way to test the C++11 Migrator than to run it on entire real projects? We’ve set up a continuous integration server to build and run cpp11-migrate on two projects so far and have plans for at least three more. For each project, the goal is to build the transformed code and run that project’s test suite to ensure semantics haven’t changed.

Implemented:

  1. LLVM 3.1
  2. ITK 4.3.1

Planned:

  1. LLDB
  2. OpenCV
  3. Poco

Running the migrator on real code has been enormously helpful for finding bugs. Real code from varying projects often reveals code expressions not accounted for in the development and unit testing of the transforms. Every time a bug found from transforming these projects gets fixed, new test cases are added to the regression test suite and the migrator becomes more robust.

Future Work

Fixing bugs found by migrating real code is of high priority right now since we want a good user experience for as many people as we can as soon as possible. Adding more transforms is another priority and those transforms with the most interest from the community will come first. Currently at the top of the list are:

  1. Use the standard library instead of TR1
  2. Replace use of the deprecated auto_ptr class.

In addition to fixing bugs and adding transforms, there are also more general improvements to consider. One such improvement we’re making progress on is to remove the restriction that only source files are transformed and not any of the headers they include. The restriction has been in place until now because the migrator needs to know which headers are safe to transform. System headers and third-party library headers clearly shouldn’t be touched.

Get Involved!

If you want to get involved, the first thing you can do is try out cpp11-migrate on your code. Bugs can be logged with LLVM’s bug tracker under the product clang-tools-extra. Send an email to the Clang Developer’s Mailing List if you need help or would like to get more involved. We look forward to hearing from you!

Posted by Edwin Vane at 5:53 AM

Labels: C++, Clang

Location: Waterloo, ON, Canada

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值