使用Visual Studio下的linux子系统来学习C++ Concepts

[原文发表地址] Learn C++ Concepts with Visual Studio and the WSL

[原文作者] Andrew Pardoe

[原文发表时间] 2017/2/22

Concepts是可以从概念上改变C++模板代码的使用. 与Coroutines,Modules,ranges特性一样,Concepts位于技术指标(TS)中, 在它们将要列入C++标准前去学习并使用这些重要的特性,是很有帮助的. 你已经可以使用VS 2017中已增加的Coroutines,Modules以及Range-V3分支中的Ranges特性. 现在我们又在VS2017针对Windows中的linux子系统模块(WSL)中支持使用Concept. 我们来看看他们是如何工作的.

关于Concepts

模板参数可以通过Concept来确定它所必须的条件, 这也是创建不同接口的本质条件. C++社区期盼很多年希望Concepts加入C++标准。 如果你对于这些事感兴趣, 可以阅读Bjarne Stroustrup写的一些关于concept背景需求的一些文章。 a recent paper about designing good concepts.如果你对于如果使用concept感兴趣, 请参考 Constraints and concepts on cppreference.com. 如果想知道关于concepts的所有细节, 你可以阅读 Concepts Technical Specification (TS).

Concepts当前仅在Gcc 6版本以上可用。 它还没有被MSVC和Clang编译器所支持。 我们计划先完成当前已经被投票通过的C++17特性, 并完成一些还没有实现的准则,然后我们就会在MSVC的TS里实现Concept.

我们可以通过VS2017包含的linux for windows子系统指定Linux shell为目标, 这样我们就可以在VS中使用concepts. 因为没有IDE界面的支持,也没有智能感应等来提高编码效率. 但是在我们熟悉的shell命令符窗体下也可以很好的学习Concepts, 毕竟我们每天都在使用command命令行窗口.

因为当前包含在WSL中的GCC版本是4.84.这个版本还不支持concepts. 我们需要先更新GCC编译器。 有两种方法,一种是安装Personal package archive(PPA)或者直接通过源码生成 GCC-6.

在安装GCC-6前, 你需要在VS2017上安装配置WSL, 参考Targeting the Windows Subsystem for Linux from Visual Studio.这篇博客. 配置好VS,并将工程目标指定到Linux. 这需要下面这些步骤,熟悉每一步将会帮助你更快的解决遇到的问题。

安装GCC-6

有两种方式可供选择, 从PPA上安装,直接通过源码生成并安装.

使用PPA安装GCC

PPA允许通过apt安装,PPA可以帮助你需要的软件. 通过安装Toolchain Test PPA ,更新apt得到最新版本的GCC. 然后安装g++-6. capture

 

PPA安装GCC,并不会把GCC设为默认编译器。 运行g++ --version会显示4.8.4版本.你可以通过使用g++-6来调用最新版本的gcc.如果gcc6不是默认编译器,你需要在你的Linux项目中将VS的远程编译器设置为GCC6. capture

从源码生成GCC

直接通过源代码生成GCC 6.3可以通过下面这几个过程.

1. 获得GCC 6.3的源码. 在下载前,需要指定源代码的URL档案, 从最近镜像mirror找到并拷贝档案URL,我将使用tar.gz作为例子。

wget https://[path to archive]/gcc-6.3.0.tar.gz

2. 使用命令解压GCC的源代码(将/mnt/c/tmp to the改为gcc-6.3.0.tar.gz的位置.

tar -xvf /mnt/c/tmp/gcc-6.3.0.tar.gz

3. 获得了GCC源代码后, 安装GCC必须的库. 参考 Installing GCC, Support libraries 以获得更多的信息. GCC需要3个前置库, 我们可以通过apt来安装它们:

sudo apt install libgmp-dev

sudo apt install libmpfr-dev

sudo apt install libmpc-dev

4. 现在我们可以生成一个目标目录,并配置GCC的生成过程, 最终得到我们需要的C++编译器.

cd gcc-6.3.0/

mkdir build

cd build

../configure --enable-languages=c,c++ --disable-multilib

5. 配置完成后, 我们可以编译GCC. 编译生成的过程需要花费一些时间, 当然我们可以使用 -J选项加快生成速度。

make –j

6. 如果生成成功没有错误, 就可以在Linux下安装GCC了, 下面这条命令将会安装GCC 6.3.0并作为默认的GCC版本.

sudo make install

You can check that GCC is now defaulting to version 6.3 with this command:

$ gcc --version

gcc (GCC) 6.3.0

Copyright (C) 2016 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO

warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

尝试在VS上使用C++ Concepts

现在可以尝试使用GCC的Concepts了! 让我们重新启动SSH服务(以防意外退出bash命令行).

sudo service ssh start

在VS上创建新的Linux项目:

添加C++源文件, 并添加使用Concepts的C++代码.下面是一个简单的Demo。这个例子很常见, 编译器对于没有定义operator==重载操作的参数i会提示错误,当然我们根据错误可以知道这里运用了concepts.

#include <iostream>

template<``classT>

concept ``boolEqualityComparable() {

    ``returnrequires(T a, T b) {

        ``{a == b}->``bool``;

        ``{a != b}->``bool``;

    ``};

}

boolis_the_answer(``constEqualityComparable& i) {

    ``return (i == 42) ? ``true : ``false``;

}

intmain() {

    ``if(is_the_answer(42)) {

        `` std::cout << ``"42 is the answer to the ultimate question of life, the universe, and everything."<< std::endl;

    ``}

    ``return0;

}

你还需要在GCC命令行开启concept. 在项目属性中的C++->Command Line对话框中加入编译选项 –fconcepts

如果你默认环境里告诉VS如何去找的编译器的地方设置的不是GCC6,你可以在项目属性页面设置:C++ > 通用 >C++编译器输入编译器的名字或者甚至是完整路径

在main函数的结尾添加断点,编译程序.打开Linux 中断你会看到输出.(Debug>Linux) F5并观察concepts在VS里是如果工作的

这样你就可以在VS IDE里面使用Concepts,Coroutines,Modules,以及Ranges特性.

举例 :concepts分派

上面的例子虽然给出了concepts的一些特性, 但是并没有做什么事情.下面是来自Casey Carter的一个目的性明确的例子, 这里使用了type trait来展示concepts的分派. 这个例子阐述了concepts分派过程中应该注意哪些约束性.

#include <iostream>

#include <type_traits>

template``<``classT>

concept ``boolIntegral = std::is_integral<T>::value;

template``<``classT>

concept ``boolSignedIntegral = Integral<T> && T(-1) < T(0);

template``<``classT>

concept ``boolUnsignedIntegral = Integral<T> && T(0) < T(-1);

template``<``classT>

void f(T ``const``& t) {

    `` std::cout << ``"Not integral: " << t << ``'\n'``;

}

void f(Integral) = ``delete``;

voidf(SignedIntegral i) {

    `` std::cout << ``"SignedIntegral: " << i << ``'\n'``;

}

voidf(UnsignedIntegral i) {

    `` std::cout << ``"UnsignedIntegral: " << i << ``'\n'``;

}

intmain() {

    ``f(42);

    ``f(1729u);

    ``f(``"Hello, World!"``);

    ``enum{ bar };

    ``f(bar);

    ``f(``'a'``);

    ``f(L``'a'``);

    ``f(U``'a'``);

    ``f(``true``);

}

结语

和往常一样, 我们欢迎你的反馈, 反馈方式可以是 visualcpp@microsoft.com Twitter @visualc, 或者 Microsoft Visual Cpp的脸书.

如果在使用VS 2017的VC++ 过程中遇到任何问题, 请通过 Report a Problem 选项, 或者VS IDE安装工具告诉我们. 使用UserVoice发送您的建议. 谢谢!