Interlude

One year down the road, 2015 has gone by but not without modifications to the C++ lands. Several Technical Specification (TS) documents were published, and heavy work continues to go into both existing and new ones. Meanwhile, work is underway for what it is intended to be C++17...

What Changed

Four new Technical Specification (TS) documents were published: The Transactional Memory TS, the Parallelism TS, the Library Fundamentals TS (v1), and the Concepts TS. Work on the Concurrency TS was finished, and it was approved for publication. Meanwhile, work on the Library Fundamentals TS v2 continues, and new work items were created for a Parallelism TS v2 as well as for a Ranges TS —based on Eric Niebler's work on ranges— and a Networking TS —based on Chris Kohlhoff's ASIO—.

The standardization committee gained a new Study Group. During CppCon 2014, there was a large number of game developers interested in ISO C++, and in contributing to the standardization process. The topics of interest to this group also happen to overlap with that of developers interested in low-latency computing outside game development, like finance and embedded. From that interest, a Study Group on Game Development and Low-Latency Computing (SG14) was born. The first meeting of this group was held in September at CppCon 2015, and the next one will take place in March at GDC 2016.

Finally, due to changes in ISO document procedures, a new numbering scheme has been introduced for naming documents. Proposals and position papers will follow the new PnnnnRm scheme, where nnnn is the four-digit stable proposal number, and m is the revision number. Administrative papers —working drafts, agendas, minutes— will continue to be ISO N -numbered documents.

C++17

Work continued into what will be the next standard, targeting 2017. The following features have been accepted into the working draft, but might be altered or even removed before the next standard is published —these changes are the ones that took place during 2015, previous changes were detailed in last year's post and can be found here—.

What's new - Language Features

__has_include

P0061 proposes to standardize the preprocessor feature __has_include , introduced in the feature-testing recommendations standing document —SD-6—. The has-include-expression searches for its argument as if it were used in an #include directive, evaluating to 1 if the search for the source file succeeds, and to 0 if the search fails.

The following example demonstrates a way to include a library optional facility only if it is available:

#if __has_include(<optional>) # include <optional> # define have_optional 1 #elif __has_include(<experimental/optional>) # include <experimental/optional> # define have_optional 1 # define experimental_optional 1 #else # define have_optional 0 #endif

Core Improvements

P0012 proposes to make exception specifications part of the type system, making the following example ill-formed:

void p() {}; void (*pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function

P0136 proposes to change the way in which inheriting constructors are implemented. A using-declaration that names a constructor now intuitively makes the corresponding base class constructors visible to initializations of the derived class, rather than declaring additional derived class constructors to forward the calls.

Core Cleanup

P0001 proposes to remove the use of the register storage-class-specifier; the keyword is still reserved and might be repurposed in the future. Any surviving use of the specifier can simply be removed to retain the original meaning.

P0002 proposes to remove the somewhat surprising increment operator for bool , deprecated since its introduction in C++98.

P0134 proposes to introduce the name default member initializer for brace-or-equal-initializers for non-static data members, and it consists of editorial changes only.

What's new - Standard Library Features

Logical Type Traits

P0013 proposes three new type traits for performing logical operations with other traits, conjunction , disjunction , and negation , corresponding to the operators && , || , and ! respectively.

// Accepts one or more arguments of the same type. template <typename T, typename... Ts> std::enable_if_t<std::conjunction<std::is_same<T, Ts>...>::value> foo(T, Ts...) {} // Accepts zero or more arguments of type int. template<typename... Ts> std::enable_if_t<std::conjunction<std::is_same<int, Ts>...>::value> bar(Ts...) {}

Constant View

P0007 proposes a helper function template as_const , which simply takes a reference and returns it as a reference to const .

template <typename T> std::add_const_t<T>& as_const(T& t) { return t } template <typename T> void as_const(T const&&) = delete;

bool_constant

N4389 proposes an alias template for std::integral_constant s of bool type:

template <bool B> using bool_constant = integral_constant<bool, B>;

shared_mutex

Before C++14 shipped, N3891 proposed to rename std::shared_mutex to std::shared_timed_mutex , as it satisfies the TimedMutex concept, leaving room for an untimed shared_mutex that only satisfied the basic Mutex concept. N4508 fills that gap by proposing an untimed shared_mutex .

Library Improvements

N4387 proposes to improve certain pair and tuple constructors by making them conditionally explicit , depending on whether any of the selected constructors for the elements are themselves explicit . This change permits the use of list initialization without opening a hole in the type system:

std::tuple<int, int> pixel_coordinates() { return {10, -15}; }

A conditionally explicit constructor is editorially represented as EXPLICIT in the standard. An implementation will have to provide two —almost identical— mutually exclusively constrained constructors:

template <typename T> struct A { template <typename U, typename std::enable_if< std::is_constructible<T, U>::value && std::is_convertible<U, T>::value, bool>::type = false> A(U&& u) : t(std::forward<U>(u)) {} template <typename U, typename std::enable_if< std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value, bool>::type = false> explicit A(U&& u) : t(std::forward<U>(u)) {} T t; };

N4510 proposes to add support for incomplete types in std::vector , std::list , and std::forward_list , allowing their use in recursive data structure definitions:

struct entry { std::list<entry> messages; /*...*/ };

The scope of the proposal is limited to those containers for which the use of incomplete type is already supported by current implementations. Future proposals are expected to explore relaxing the remaining —allocating— containers.

N3932 proposed to add to the Library Fundamentals TS variable templates with a _v suffix as a less verbose synonym for type traits that yield a ::value . P0006 proposes to merge those into the working draft for C++17.

static_assert(!std::is_same_v<short, int>);

P0092 proposes to add rounding operations for duration s and time_point s, as well as an abs overload for signed duration types.

using namespace std::chrono; milliseconds ms(2500); std::cout << floor<seconds>(ms).count() << "s

"; // 2s std::cout << round<seconds>(ms).count() << "s

"; // 2s std::cout << ceil<seconds>(ms).count() << "s

"; // 3s

P0156 proposes to extend std::lock_guard to support multiple locks.

void swap(MyType& l, MyType& r) { std::lock_guard<std::mutex, std::mutex> lck(l.mtx, r.mtx); /* ... */ }

P0074 proposes to make std::owner_less more flexible by introducing an std::owner_less<void> specialization —following C++14's transparent operators—, capable of handling comparisons of smart pointers of different types, and without introducing any temporaries.

Library Cleanup

P0004 proposes to remove old iostreams members, which used to alias other types or member functions for compatibility reasons, deprecated since their introduction in C++98.

TS

A lot of work is going on in the form of Technical Specifications (TS). Each TS would deserve and entire post —or several— in order to do justice to them; what follows is merely a glance at what they have to offer.

Library Fundamentals v2

N4388 proposes to add a propagate_const wrapper class that propagates const -ness to pointer-like member objects. Within a const member function, all —non- mutable — member objects are seen as const too, but const -ness is shallow; for pointer and pointer-like members, this means the pointers themselves are const while the thing they point to remains unaffected:

struct A { void foo() { std::cout << "non-const" << std::endl; } void foo() const { std::cout << "const" << std::endl; } }; struct B { std::unique_ptr<A> _that_a = std::make_unique<A>(); void bar() { _that_a->foo(); } // prints "non-const" void bar() const { _that_a->foo(); } // prints "non-const" too };

This might be undesirable on occasion, and even surprising to some. The propagate_const wrapper class is introduced to automatically address this situation, without having to const_cast every access to a pointer or pointer-like member:

struct C { std::experimental::propagate_const< std::unique_ptr<A>> _that_a = std::make_unique<A>(); void bar() { _that_a->foo(); } // prints "non-const" void bar() const { _that_a->foo(); } // prints "const" };

N4502 proposes to add a detection toolkit for type introspection. It identifies a common pattern for type introspection —popularized by void_t —, which it calls the detection idiom:

// primary template handles types that have no nested `type` member template <typename, typename = void> struct has_type_member : std::false_type {}; // specialization recognizes types that do have a nested `type` member template <typename T> struct has_type_member<T, std::void_t<typename T::type>> : std::true_type {};

This idiom is encapsulated in a self-contained metafunction that is parameterized on an archetypal expression:

// has_type_member revisited template <typename T> using type_member_t = typename T::type; template <typename T> using has_type_member = std::experimental::is_detected<T, type_member_t>; // ...and more template <typename T> using copy_assign_t = decltype(std::declval<T&>() = std::declval<T const &>()); template <typename T> using is_copy_assignable = std::experimental::is_detected<T, copy_assign_t>;

N4519 proposes to add a feature to allow a function to capture information about the source code calling it. This is the first of the reflection proposals to materialize, and it intends to replace use of macros such as __FILE__ , __LINE__ and __func__ .

void log_debug(std::string const& message, std::experimental::source_location loc = std::experimental::source_location::current()) { std::clog << loc.file_name() << ":" << loc.line_number() << ":" << loc.column() << ":" << loc.function_name() << ":" << message << std::endl; }

N4391 proposes to add a make_array creation function to deduce both element type and array bound in an std::array , as well as an additional to_array function that creates an std::array from a core language one.

auto arr = std::experimental::make_array(0, 1, 2); // std::array<int, 3> auto str = std::experimental::to_array("012"); // std::array<char, 4>

N4531 proposes a direct replacement to the deprecated std::rand —dubbed "baby's first rand"—, with a per-thread uniform random number generator.

std::experimental::randint(0, 6); // randomly seeded std::experimental::reseed(0); // for debugging purpose std::experimental::shuffle(begin(v), end(v)); std::experimental::reseed(); // back to random

Parallelism v2

A second version of the Parallelism TS was started. It builds on the first by adding task blocks as proposed by P0155, with the goal of writing expressive and portable fork-join parallel code:

template <typename F> int traverse(node* n, F compute) { int left = 0, right = 0; std::experimental::parallel::define_task_block( [&](std::experimental::parallel::task_block& tb) { if (n->left) tb.run([&] { left = traverse(n->left, compute); }); if (n->right) tb.run([&] { right = traverse(n->right, compute); }); }); return compute(n) + left + right; }

Each call to run spawns a task, a unit of work that is allowed to execute in parallel with respect to the caller. The define_task_block function delineates a region in the program containing all those tasks spawned, which are all joined back to a single thread on return from define_task_block .

Ranges

A new work item was created for the Ranges TS. In this first step, foundational and iterator concepts are reformulated using the syntax of the Concept TS, and algorithms are respecified in terms of these new concepts. Additionally, new algorithm overloads are added that take iterable objects, rather than pairs of iterators. Furthermore, constraints are relaxed to permit the use of sentinels to denote the end of a range.

int main() { using namespace std::experimental::ranges; auto v = std::vector<std::string>{"this", "is", "a", "test"}; auto out = ostream_iterator<std::string>{std::cout, " "}; sort(v); copy(v, out); std::cout << '

'; auto result = reverse_copy(v, out); std::cout << '

'; return !(result.in() == end(v)); }

This paper does not specify any new range views, actions, facades, or adaptor utilities yet.

Networking

A new work item was created for the Networking TS. It brings sockets programming —as seen in Boost.ASIO—to the standard library:

using namespace std::experimental::net; // echoes the characters it receives back to the client in upper case, synchronous void sync_connection(ip::tcp::socket& socket) { try { std::vector<char> buffer_space(1024); for (;;) { std::size_t length = socket.read_some(buffer(buffer_space)); uppercase(buffer_space.begin(), buffer_space.begin() + length); write(socket, buffer(buffer_space, length)); } } catch (std::system_error& e) { /* ...*/ } }

That's it?

This is by no means an exhaustive list! Furthermore, there's plenty of work in the pipeline —not yet approved into a working draft—, targeting the standard itself or one of the several TSes.

The modules study group has reached consensus on the design for a first phase, and is expected to provide formal wording for what will soon become a Modules TS.

The controversial variant has reached design agreement. Going forward, it will look a lot like the Lenexa compromise one, but access to an invalid variant will throw an exception rather than triggering undefined behavior.

The coroutines proposal made progress and it is working on formal wording for C++17 —some members of the committee think that they belong in a TS instead—.

The contracts initiative gains momentum, as proponents of different proposals have agreed in the core details.

...and much, much more.

During 2015, the C++ lands grew bigger at an outstanding rate! As the TS model —which allows to decouple and publish work independently from the standard— is proving to be a success, 2016 it's certainly looking to be a good year for C++...

This blog runs on Nibbleblog, a powerful engine for creation and manipulation of blogs; it's generated by Markdown, a powerful yet clean text-to-HTML conversion tool; and uses Syntax Highlighter, a fully functional self-contained code syntax highlighter, for its code snippets.