01 Jan, 2015

Interlude

One year down the road, 2014 has gone by but not without modifications to the C++ lands. C++14 was completed, and Clang has already reached full conformance! But it's not the end of the road, while the Technical Specification (TS) documents continue to move forward, work has started on what it is intended to be C++17...

C++14

Last time we stopped and looked at the landscape, C++14 had completed its primary comment international ballot (Committee Draft, aka "CD"). After those comments where addressed, in February 2014 the Draft International Standard (aka "DIS") was started. The new draft included some minor changes, as well as several issue resolutions and editorial improvements.

C++14: We’re done! (we think)

Winter ISO C++ meeting, C++14 is done!

In August 2014, C++14 completed its final international ballot.

Clang reached full C++14 conformance, language features and standard library features, as of v3.4, and it already implements some C++17 features —details here—.

GCC became C++14 feature complete as of the not-yet-released v5, and standard library features are expected to follow soon —details here—.

Visual C++ continues to run behind, but it has picked up the pace to cover the conformance gap. The latest preview includes most C++11 features, some C++14 features, and even some features that may or may not turn to be C++17 features —details here—.

What changed

These changes are the ones that took place during 2014, previous changes were detailed in last year's post and can be found here.

Adding tuple_element_t

The TransformationTraits redux had already added to C++14 template aliases for all transformation type traits in <type_traits>. N3887 applies the same guideline to the rest of the standard library, and adds the only missing template alias: std::tuple_element_t.

A proposal to rename shared_mutex to shared_timed_mutex

The std::shared_mutex introduced in C++14 satisfied the TimedMutex concept, as it provided timed blocking functionality. For consistency, and in order to leave room for a future mutex that only satisfied the basic Mutex concept, N3891 renamed std::shared_mutex to std::shared_timed_mutex.

Discouraging rand

The legacy C random number generation facility has been superseded by those introduced in C++11. Unlike rand, the new facilities specify the underlying algorithm used, and avoid any implicitly shared state such that they may be safely used in multi-threaded environments. A note in rand suggested to migrate to <random> instead. N3924 further discourages the use of rand by strengthening the existing note:

26.8 [c.math]/5 The rand function has the semantics specified in the C standard, except that the implementation may specify that particular library functions may call rand. It is implementation-defined whether the rand function may introduce data races (17.6.5.9). [Note: The random number generation (26.5) facilities in this standard are often preferable to rand, because rand’s underlying algorithm is unspecified. Use of rand therefore continues to be nonportable, with unpredictable and oft-questionable quality and performance. -end note]

Additionally, it deprecates std::random_shuffle. One of its overloads depends on rand, which is strongly discouraged; while the other one is cumbersome to use, and its behavior can be obtained in a simpler way by using std::shuffle.

C++17

With C++14 ready, 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.

What's new - Language Features

Fold Expressions

N4295 proposes a new kind of primary expression that allows parameter packs to be expanded as a sequence of operators. These fold expressions recursively apply a binary operator to the arguments in a parameter pack.

// before
auto verbose_and_sometimes_problematic_sum() {
  return 0;
}

template <typename T>
auto verbose_and_sometimes_problematic_sum(T t) {
  return t;
}

template<typename T, typename... Ts>
auto verbose_and_sometimes_problematic_sum(T t, Ts... ts) {
  return t + verbose_and_sometimes_problematic_sum(ts...);
}

// now
template <typename... Ts>
auto fold_expression_sum(Ts... ts) {
  return (ts + ...);
}

This is in part motivated by the need of the upcoming Concepts TS to declare constrained template parameter packs.

template<typename... Ts> requires (Integral<Ts> && ...)
void foo(Ts...);

Core Improvements

N3922 proposes to change the deduction rules for auto, which are somewhat special as they will attempt to deduce an std::initializer_list<T> type for a braced-init-list —which doesn't really have a type—. Under the new rules, an std::initializer_list will no longer be deduced when direct-initialization is employed, which shall have a single element.

auto x1{ 0 }; // decltype(x1) is std::initializer_list<int> before, int now
auto x2{ 1, 2 }; // decltype(x2) is std::initializer_list<int> before, error now: not a single initializer-clause
auto x3 = { 0 }; // decltype(x3) is std::initializer_list<int>
auto x4 = { 1, 2 }; // decltype(x4) is std::initializer_list<int>

N3928 proposes to allow omitting the string literal for static_assert.

static_assert(std::is_pod<X>::value, "oops!"); // ok
static_assert(std::is_pod<X>::value); // error before, ok now

N4051 proposes to allow the use of typename instead of class when declaring a template template parameter. Since the introduction of alias templates, template template arguments need not be class templates.

template<typename T> struct A {};
template<typename T> using B = int;

template<template<typename> class X> struct C; // ok
C<A> ca; // ok
C<B> cb; // ok, not a class template

template<template<typename> typename X> struct D; // error before, ok now

N4230 proposes to allow the use of a qualified name in a namespace definition.

namespace A { namespace B { namespace C { /*...*/ } } }
namespace A::B::C { /*...*/ } // equivalent to above

N4259 proposes a replacement for std::uncaught_exception. It has long been known that std::uncaught_exception is of little or no use; it simply flags whether there is an active exception in flight —one that hasn't yet been caught—, and thus whether stack unwinding is in progress somewhere along the call stack. The newly introduced std::uncaught_exceptions returns the number of active exceptions instead, which is enough to make it useful; the old std::uncaught_exception is deprecated.

class scope_guard {
  int const uncaught_exceptions;
  /*...*/

public:
  scope_guard(/*...*/)
    : uncaught_exceptions(std::uncaught_exceptions())/*, ...*/
  {}

  ~scope_guard() {
    if (std::uncaught_exceptions() == uncaught_exceptions) {
      std::cout << "died of natural causes";
    } else {
      std::cout << "killed by stack unwinding";
    }
  }
};

N4266 proposes to allow specifying attributes on enumerators and namespaces, and extends the [[deprecated]] attribute to apply to them.

enum E {
  foobar = 0,
  foobat [[deprecated]] = foobar
};

N4267, proposes to add support for u8 character literals. The set of characters representable with a single UTF-8 code unit is exactly that of ASCII, so these new literals —e.g., u8'w'— guarantee ASCII encoding, as well as improve consistency within the language.

N4268 proposes to relax the restrictions on non-type template arguments for pointers, references, and pointers to members.

template<int *p> struct A {};
int n;
A<&n> a; // ok

constexpr int *p() { return &n; }
A<p()> b; // error before, ok now

A note on Terse Range-Based For-Loops

A curious case is that of N3994. It reckons that range-based for-loops are prone to be written as for (auto elem : range), which it deems as "very bad" as it produces copies of each element. It proposes the terser syntax for (elem : range) as a novice friendly equivalent of for (auto&& elem : range).

This feature was approved by the Evolution Working Group, but with the ballot underway it couldn't be voted into the working draft. When the time came for the full committee to vote on it, the feature was rejected. The concern was that this novel form of introducing names —that doesn't mention a type nor placeholder— proved to be surprising. It was furthermore noted that copying by default is inherent to C++'s nature, and has to be taught regardless.

T *x = nullptr;
for (x : values) { if (/*...*/) break; } // this introduces a new x!
if (x) { /*...*/ } // outer x was never touched

This feature may return in the future in a different form.

Core Cleanup

N4086 proposes to remove —not deprecate— trigraphs from the language. It points out that trigraphs are not needed in the standard, since trigraph replacement can already be part of the implementation-defined mapping form physical source file characters to basic source characters.

N4262 proposes to introduce the term forwarding reference to refer to variables or parameters of type T&& where T is deduced. While these look like rvalue references, deduction rules dictate that T will be deduced as an lvalue reference when the argument is an lvalue, which due to reference collapsing results in an lvalue reference. Scott Meyers recognized this special case needed a special name, and so dubbed them universal references. This name was considered misleading to "the committee", with forwarding references being clearer as they were designed to support perfect forwarding.

N4285 proposes to adjust the wording for exceptions, and consists of —sizable— editorial changes only.

What's new - Standard Library Features

void_t

N3911 proposes to add void_t as a variadic template alias for void, which has proven useful in SFINAE contexts.

template <typename T, typename = void>
struct has_type_member : std::false_type {};

template <typename T>
struct has_type_member<T, void_t<typename T::type>> : std::true_type {};

struct foo { using type = int; };
static_assert(has_type_member<foo>::value);
// typename T::type is well-formed, matches the specialization

struct bar {};
static_assert(!has_type_member<bar>::value);
// typename T::type is not well-formed,
// the specialization is not viable due to SFINAE, matches the base template

invoke

N4169 proposes to introduce the function template std::invoke for invoking any callable types, with the semantics of the pseudo-macro INVOKE.

Non-member size and more

N4280 proposes to add non-member functions size, empty and data, akin to std::begin/std::end.

Library Improvements

N4089 proposes to allow conversions from std::unique_ptr<T[]> when they are known to be safe, like qualification-conversions.

N4277 proposes to make std::reference_wrapper<T> a trivially copyable type.

N4279 proposes to add new interfaces for unique-key maps:

  • try_emplace inserts an element into the map only if the key does not exist already; otherwise there is no effect —in particular, it does not modify its arguments—.
  • insert_or_assign inserts the mapped element or assigns it to the current element if the key already exists; similar to operator[], but does not require default-constructibility.

Library Cleanup

N4190 proposes to remove features that have been deprecated for years and superseded by modern features.

  • std::unary_function/binary_function: these helpers are unnecessary given C++11's perfect forwarding, decltype, etc.
  • std::ptr_fun: function pointers no longer need to be wrapped.
  • std::mem_fun/std::mem_fun_ref: superseded by std::mem_fn.
  • std::bind1st/std::bind2nd: superseded by std::bind.
  • std::auto_ptr: superseded by std::unique_ptr.
  • std::random_shuffle: prefer std::shuffle.

N4258 proposes to add or fix uses of noexcept in the library.

N4284 proposes to introduce the term contiguous iterator as a refinement of random-access iterator, but does not introduce a corresponding std::contiguous_iterator_tag nor any new functionality.

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.

Filesystem

The Filesystem TS —based on Boost.Filesystem v3 was approved. It provides facilities to manipulate files and directories, and the paths that identify them.

namespace filesystem = std::experimental::filesystem;

filesystem::path const& p = /*...*/;
try {
  if (filesystem::exists(p)) {
    if (filesystem::is_regular_file(p)) {
      std::cout << p << " size is " << filesystem::file_size(p) << '\n';
    } else if (filesystem::is_directory(p)) {
      std::cout << p << " is a directory containing:\n";

      std::copy(filesystem::directory_iterator(p), filesystem::directory_iterator(),
        std::ostream_iterator<filesystem::directory_entry>(std::cout, "\n"));
    } else {
      std::cout << p << " exists, but is neither a regular file nor a directory\n";
    }
  } else {
    std::cout << p << " does not exist\n";
  }
} catch (filesystem::filesystem_error const& ex) {
  std::cerr << ex.what() << '\n';
}

Library Fundamentals

The Library Fundamentals TS went through its first round of international ballot. It provides a bundle of general purpose facilities:

  • N3793 proposes optional<T> —based on Boost.Optional—, a type that may or may not store a value of type T in its storage space. Its interface allows to query if a value of type T is currently stored, and if so, to access it.

    template <typename T>
    std::experimental::optional<T> biggest(std::vector<T> const& vs) {
      std::experimental::optional<T> biggest; // initialized to nullopt
      for (T const& e : vs) {
        if (!biggest || *biggest < e) {
          biggest = e;
        }
      }
      return biggest;
    }
  • N3804 proposes any —based on Boost.Any—, a type-safe container for single values of value types.

    using many = std::list<std::experimental::any>;
    
    template <typename T>
    void append_any(many& values, T const& value) {
        values.push_back(value);
    }
    
    void append_nothing(many& values) {
        values.push_back(std::experimental::any());
    }
  • N3866 proposes invocation_type, a new trait whose member typedef type is the implied function type of a callable object when called with the given argument types.

    struct C {
      int operator()(double d, int i);
      int operator()(double d1, double d2);
    };
    
    static_assert(std::is_same<
      std::experimental::invocation_type_t<C(int, int)>,
      int(double, int)>::value); // holds
  • N3905 proposes an overload of std::search taking an additional searcher object, which can carry precomputed information or statistics about the pattern being searched for. A default searcher object is provided, as well as searcher objects for the "Boyer-Moore" and "Boyer-Moore-Horspool" algorithms.

    // existing code
    std::experimental::search(
      corpus_first, corpus_last, 
      pattern_first, pattern_last);
    
    // same code, new interface
    std::experimental::search(
      corpus_first, corpus_last, 
      std::experimental::make_default_searcher(pattern_first, pattern_last));
    
    // same code, different algorithm
    std::experimental::search(
      corpus_first, corpus_last, 
      std::experimental::make_boyer_moore_searcher(pattern_first, pattern_last));
  • N3915 proposes apply, a facility that allows to call a function object with elements from a tuple as arguments. This functionality was previously included in the C++14 standard as an example on the use of compile-time integer sequences.

    void foo(int bar, std::string baz){ /*...*/ }
    
    std::tuple<int, std::string> args = /*...*/;
    std::experimental::apply(foo, args);
  • N3916 proposes facilities for decoupling an object's type from the allocator it uses to obtain memory. This is accomplished via the introduction of a memory_resource abstract class, which describes how blocks can be allocated and deallocated; the picture is completed with a polymorphic_allocator<T>, which wraps a pointer to a memory_resource in an Allocator interface, and a resource_adaptor<Allocator>, which wraps an Allocator in a memory_resource interface. Additionally, for each standard allocator-aware container, the pmr namespace provides an alias that uses a polymorphic_allocator<T>.

    void foo(std::experimental::pmr::vector<int> const&);
    
    std::experimental::pmr::vector<int> v1; // uses pmr::get_default_resource
    foo(v1);
    
    std::experimental::monotonic_buffer_resource res;
    std::experimental::pmr::vector<int> v2(&res);
    foo(v2);
  • N3920 proposes to add array support to shared_ptr, via the syntax shared_ptr<T[]> and shared_ptr<T[N]>, alike those of unique_ptr.

    std::experimental::shared_ptr<double[]> p1(new double[n]);
    std::experimental::shared_ptr<double[1024]> p2(new double[1024]);
    
    p1[x] = p2[x] = /*...*/;
  • N3921 proposes string_view, a read-only reference to a —non-null-terminated— contiguous sequence of characters. It's a drop-in replacement of std::string const&, as it implements all of std::string's const member functions —even the cruft—.

    void okayish(std::string const&){ /*...*/ }
    constexpr void better(std::experimental::string_view){ /*...*/ }
    
    okayish("yadda yadda yadda"); // std::string temporary allocates memory
    better("yadda yadda yadda"); // no memory allocation
  • N3925 proposes sample, an algorithm for random sampling —picking a given number of elements from a range—

    std::vector<int> const population = {1, 2, 3, 4, 5};        
    std::vector<int> sample;
    
    std::random_device rd;
    std::mt19937 g(rd());
    std::experimental::sample(
      population.begin(), population.end(),
      std::back_inserter(sample), 3, g);
  • N3932 proposes to add variable templates with a _v suffix as a less verbose synonym for type traits that yield a ::value.

    static_assert(std::experimental::is_same_v<short, 
      std::tuple_element_t<2, std::tuple<long, int, short, char>>>);

The draft included facilities for network byte order conversion, proposed by N3787, but those did not survive the ballot. The concern was that the corresponding POSIX facilities —htonl, htons, ntohl and ntohs— may be defined as macros, possibly resulting in conflicts when defining and/or calling such functions.

But it doesn't end there...

Library Fundamentals v2

As soon as the Library Fundamentals TS was ready, version 2 was started.

  • N4061 proposes gcd and lcm algorithms, which calculate the greatest common divisor and the least common multiple of two integer values, respectively.

    static_assert(std::experimental::gcd(6, 15) == 3);
    static_assert(std::experimental::lcm(6, 15) == 30);
  • N4076 proposes not_fn, a generalized callable negator facility.

    std::partition(v.begin(), v.end(), [f](auto& p) { return !f(p); }); // before
    std::partition(v.begin(), v.end(), std::experimental::not_fn(f)); // after
  • N4257 proposes ostream_joiner, a class that acts like ostream_iterator except that the delimiter is only placed between output elements.

    std::vector<int> v = {1, 4, 6};
    
    // Prints "1, 4, 6, "
    std::copy(v.cbegin(), v.cend(), 
      std::ostream_iterator<int>(std::cout, ", "));
    
    // Prints "1, 4, 6"
    std::copy(v.cbegin(), v.cend(), 
      std::experimental::make_ostream_joiner(std::cout, ", "));
  • N4273 proposes erase and erase_if, uniform facilities to eliminate elements from a container, which takes different forms for different kind of containers.

    std::vector<int> v = {1, 2, 3, 4};
    
    v.erase(std::remove_if(v.begin(), v.end(), /*...*/), v.end()); // before
    std::experimental::erase_if(v.begin(), v.end(), /*...*/); // after
  • N4282 proposes observer_ptr, a —not very— smart pointer that takes no ownership for the objects it observes.

    void raw(int*);
    void observer(std::experimental::observer_ptr<int>);
    
    int x = 42;
    raw(&x); // fine?
    observer(std::experimental::make_observer(&x)); // fine!

Parallelism

The Parallelism TS also went through its first round of international ballot. It provides a series of algorithms with parallel execution semantics; some of them are counterparts of the existing algorithms, while others are new.

    std::vector<int> vec = /*...*/;

    // explicit sequential sort
    std::experimental::parallel::sort(
      std::experimental::parallel::seq, vec.begin(), vec.end());

    // parallel sort
    std::experimental::parallel::sort(
      std::experimental::parallel::par, vec.begin(), vec.end());

    // vectorized sort
    std::experimental::parallel::sort(
      std::experimental::parallel::par_vec, vec.begin(), vec.end());

    // sort with dynamically-selected execution
    size_t threshold = /*...*/;
    std::experimental::parallel::execution_policy exec =
      std::experimental::parallel::seq;
    if(vec.size() > threshold) {
      exec = std::experimental::parallel::par;
    }
    std::experimental::parallel::sort(exec, vec.begin(), vec.end());

Transactional Memory

The Transactional Memory TS is currently in its first round of international ballot. It provides language constructs for transactional memory, a form of optimistic speculation in which transactions are allowed to run concurrently but must yield a result equivalent to that of some sequential execution —they appear to execute atomically—. Transactions are represented by atomic blocks, which shall not execute transaction-unsafe code. Additionally, it provides synchronized blocks which execute as-if holding a global mutex.

    int a = 1, b = 2, c = 3;
    int r1 = 0, r2 = 0, r3 = 0;
    std::thread t1([]{
      atomic_noexcept { // or atomic_commit/atomic_cancel
        a = 2;
        b = a + 1;
        c = b + 1;
      }
    });
    std::thread t2([]{
      atomic_noexcept {
        r1 = a;
        r2 = b;
        r3 = c;
      }
    });

    t1.join();
    t2.join();

    // either r1 == 1, r2 == 2, r3 == 3,
    // or r1 == 2, r2 == 3, r3 == 4

Concepts

The Concepts TS will be heading for its first round of international ballot soon. It provides language extensions that enable the specification and checking of constraints on template arguments, and the ability to overload functions and specialize templates based on those constraints.

    template <typename C>
    concept bool Container() {
      return requires(C c) {
        typename C::value_type;
        typename C::iterator;
        /*...*/
        { c.begin() } -> C::iterator;
        { c.end() } -> C::iterator;
        /*...*/
      };
    }

    template <typename T> requires Container<T>
    void foo(T const&); // or,

    template <Container T>
    void foo(T const&); // or,

    void foo(Container const&);

Concurrency

The Concurrency TS is still in flux. The working draft currently includes extensions for futures that make them composable —.then and friends—, and its likely to incorporate latches, barries, and atomic smart pointers soon. Executors, which were part of the original working draft, were removed due to concerns with their design —but may return in a different form—.

    void answer_to_life_the_universe_and_everything() { return 42; }

    std::experimental::future<int> f1 =
        std::experimental::async(&answer_to_life_the_universe_and_everything);

    /*...*/

    std::experimental::future<std::string> f2 = f1.then([](auto f) {
      return std::to_string(f.get()); // here .get() won't block
    });

    /*...*/

    std::cout << f2.get();

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 Networking TS was rebooted; there was a request to update a networking proposal for TR2 —based on Boost.Asio —, which is now N4332.

  • Concurrency is looking at facilities like coroutines and fibers —light threads of execution—, as proposed by N4286, N4232 and N4244.

  • Ranges are coming to the standard library town, as proposed by N4128.

  • ...and much, much more.

During 2014, 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, 2015 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.