使用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.
PPA安装GCC,并不会把GCC设为默认编译器。 运行g++ --version会显示4.8.4版本.你可以通过使用g++-6来调用最新版本的gcc.如果gcc6不是默认编译器,你需要在你的Linux项目中将VS的远程编译器设置为GCC6.
从源码生成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发送您的建议. 谢谢!