Learn C++ Concepts with Visual Studio and the WSL

Andrew

February 22nd, 2017

点这里看中文版

Concepts promise to fundamentally change how we write templated C++ code. They’re in a Technical Specification (TS) right now, but, like Coroutines, Modules, and Ranges, it’s good to get a head start on learning these important features before they make it into the C++ Standard. You can already use Visual Studio 2017 for Coroutines, Modules, and Ranges through a fork of Range-v3. Now you can also learn Concepts in Visual Studio 2017 by targeting the Windows Subsystem for Linux (WSL). Read on to find out how!

About concepts

Concepts enable adding requirements to a set of template parameters, essentially creating a kind of interface. The C++ community has been waiting years for this feature to make it into the standard. If you’re interested in the history, Bjarne Stroustrup has written a bit of background about concepts in a recent paper about designing good concepts. If you’re just interested in knowing how to use the feature, see Constraints and concepts on cppreference.com. If you want all the details about concepts you can read the Concepts Technical Specification (TS).

Concepts are currently only available in GCC 6+. Concepts are not yet supported by the Microsoft C++ Compiler (MSVC) or Clang. We plan to implement the Concepts TS in MSVC but our focus is on finishing our existing standards conformance work and implementing features that have already been voted into the C++17 draft standard.

We can use concepts in Visual Studio 2017 by targeting the Linux shell running under WSL. There’s no IDE support for concepts–thus, no IntelliSense or other productivity features that require the compiler–but it’s nice to be able to learn Concepts in the same familiar environment you use day to day.

First we have to update the GCC compiler. The version included in WSL is currently 4.8.4–that’s too old to support concepts. There are two ways to accomplish that: installing a Personal Package Archive (PPA) or building GCC-6 from source.

But before you install GCC-6 you should configure your Visual Studio 2017 install to target WSL. See this recent VCBlog post for details: Targeting the Windows Subsystem for Linux from Visual Studio. You’ll need a working setup of VS targeting Linux for the following steps. Plus, it’s always good to conquer problems in smaller pieces so you have an easier time figuring out what happened if things go wrong.

Installing GCC-6

You have two options for installing GCC-6: installing from a PPA or building GCC from source.

Using a PPA to install GCC

A PPA allows developers to distribute programs directly to users of apt. Installing a PPA tells your copy of apt that there’s another place it can find software. To get the newest version of GCC, install the Toolchain Test PPA, update your apt to find the new install locations, then install g++-6.

[text] sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update sudo apt install g++-6 [/text]

The PPA installs GCC as a non-default compiler. Running g++ --version shows version 4.8.4. You can invoke GCC by calling g++-6 instead of g++ . If GCC 6 isn’t your default compiler you’ll need to change the remote compiler that VS calls in your Linux project (see below.)

[text] g++ –version g++-6 –version [/text]

Building GCC from source

Another option is to build GCC 6.3 from source. There are a few steps, but it’s a straightforward process.

First you need to get a copy of the GCC 6.3 sources. Before you can download this to your bash shell, you need to get a link to the source archive. Find a nearby mirror and copy the archive’s URL. I’ll use the tar.gz in this example: [text] wget http://[path to archive]/gcc-6.3.0.tar.gz [/text] The command to unpack the GCC sources is as follows (change /mnt/c/tmp to the directory where your copy of gcc-6.3.0.tar.gz is located): [text] tar -xvf /mnt/c/tmp/gcc-6.3.0.tar.gz [/text] Now that we’ve got the GCC sources, we need to install the GCC prerequisites. These are libraries required to build GCC. (See Installing GCC, Support libraries for more information.) There are three libraries, and we can install them with apt: [text] sudo apt install libgmp-dev sudo apt install libmpfr-dev sudo apt install libmpc-dev [/text] Now let’s make a build directory and configure GCC’s build to provide C++ compilers: [text] cd gcc-6.3.0/ mkdir build cd build ../configure –enable-languages=c,c++ –disable-multilib [/text] Once that finishes, we can compile GCC. It can take a while to build GCC, so you should use the -j option to speed things up. [text] make -j [/text] Now go have a nice cup of coffee (and maybe watch a movie) while the compiler compiles. If make completes without errors, you’re ready to install GCC on your system. Note that this command installs GCC 6.3.0 as the default version of GCC. [text] sudo make install [/text] You can check that GCC is now defaulting to version 6.3 with this command: [text] $ 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. [/text]

Trying out Concepts in VS

Now that you’ve updated GCC you’re ready to try out concepts! Let’s restart the SSH service again (in case you exited all your bash instances while working through this walkthrough) and we’re ready to learn concepts!

[text] sudo service ssh start [/text]

Create a new Linux project in VS:

Add a C++ source file, and add some code that uses concepts. Here’s a simple concept that compiles and executes properly. This example is trivial, as the compile would fail for any argument i that doesn’t define operator== , but it demonstrates that concepts are working.

[cpp] #include <iostream>

template <class T> concept bool EqualityComparable() { return requires(T a, T b) { {a == b}->bool; {a != b}->bool; }; }

bool is_the_answer(const EqualityComparable& i) { return (i == 42) ? true : false; }

int main() { if (is_the_answer(42)) { std::cout << "42 is the answer to the ultimate question of life, the universe, and everything." << std::endl; } return 0; } [/cpp]

You’ll also need to enable concepts on the GCC command line. Go to the project properties, and in the C++ > Command Line box add the compiler option -fconcepts .

If GCC 6 isn’t the default compiler in your environment you’ll want to tell VS where to find your compiler. You can do that in the project properties under C++ > General > C++ compiler by typing in the compiler name or even a full path:

Now compile the program and set a breakpoint at the end of main . Open the Linux Console so you can see the output (Debug > Linux Console). Hit F5 and watch concepts working inside of VS!

Now we can use Concepts, Coroutines, Modules, and Ranges all from inside the same Visual Studio IDE!

Example: concept dispatch

The example above shows that concepts compile properly but it doesn’t really do anything. Here’s a more motivating example from Casey Carter that uses a type trait to show concept dispatch. This is a really great example to work through to illustrate the mechanics of constraints.

[cpp] #include <iostream> #include <type_traits>

template<class T> concept bool Integral = std::is_integral<T>::value;

template<class T> concept bool SignedIntegral = Integral<T> && T(-1) < T(0);

template<class T> concept bool UnsignedIntegral = Integral<T> && T(0) < T(-1);

template<class T> void f(T const& t) { std::cout << "Not integral: " << t << ‘

’; }

void f(Integral) = delete;

void f(SignedIntegral i) { std::cout << "SignedIntegral: " << i << ‘

’; }

void f(UnsignedIntegral i) { std::cout << "UnsignedIntegral: " << i << ‘

’; }

int main() { f(42); f(1729u); f("Hello, World!"); enum { bar }; f(bar); f(‘a’); f(L’a’); f(U’a’); f(true); } [/cpp]

In closing

As always, we welcome your feedback. Feel free to send any comments through e-mail at visualcpp@microsoft.com, through Twitter @visualc, or Facebook at Microsoft Visual Cpp.

If you encounter other problems with Visual C++ in VS 2017 please let us know via the Report a Problem option, either from the installer or the Visual Studio IDE itself. For suggestions, let us know through UserVoice. Thank you!