UPDATE: although the book is now available both on packtpub.com and Amazon.com, it still appears on Amazon that “This title will be released on August 4, 2017”. The reason for this is that it takes 2-12 days for reprocessing a title update on Amazon.

I am pleased to announce that my book on modern C++ programming has been published by PacktPub. The book is called Modern C++ Programming Cookbook and can be ordered at packtpub.com and Amazon. The complete table of contents is available below.

The front cover

The book is organized in recipes, much like a cookbook (therefore the name). These recipes are organized in sections that introduce you to the topic, list any necessary pre-requisites and then explain how to do something and how that works. Throughout 112 recipes, the book covers both language and library features from C++11, C++14 and C++17, including the libraries for strings, containers, algorithms, iterators, input/output, regular expressions, threads, filesystem, atomic operations, and utilities. Besides that, there is a chapter for patterns and idioms and one dedicated for testing frameworks, that covers everything you need to know to get started with Boost.Test, Google Test and Catch.

This book is intended for all C++ developers, regardless of their experience. The beginner and intermediate developers will benefit the most from the book in their attempt to become prolific with C++. Experienced C++ developers, on the other hand, will find a good reference for many C++11, C++14, and C++17 language and library features that may come in handy from time to time. However, the book requires prior basic knowledge of C++, such as functions, classes, templates, namespaces, macros, and others. If you are not familiar with C++ at all, you should first read an introductory book to familiarize yourself with the core aspects.

Although C++17 has not yet been ratified as an ISO standard, the final version that is up for the ballot is well defined. In my book I discuss most of the important language and library features that made it into C++17. The C++17 features discussed in the book are:

  • structured bindings
  • fold expressions
  • constexpr if
  • new attributes ([[fallthrough]], [[nodiscard]], [[maybe_unused]])
  • new type deduction rules for list initialization
  • range based for loops improvements
  • general form of lambda expressions
  • std::invoke() and std::apply()
  • static_assert changes
  • non-member container access functions std::data(), std::size(), and std::empty()
  • std::search() searchers (Boyer-Moore and Boyer-Moore-Horspool)
  • chrono changes (floor(), round(), ceil(), and abs())
  • std::any
  • std::optional
  • std::variant (2 recipes)
  • std::string_view
  • std::scoped_lock
  • filesystem library (5 recipes)
  • shared_ptr and unique_ptr changes

All the samples in the book have been tested with VC++ 2017 (where possible), GCC 7 and Clang 5. All the language and library features discussed in the book are available with these versions of the mentioned compilers, except for a few exceptions for VC++. At this time, the following features are still not supported in VC++:

  • structured bindings
  • fold expressions
  • constexpr if
  • searchers for std::search()

If you do not have the latest versions of these compilers, you can try all the samples in the book with an online compiler. gcc and Clang are available at wandbox.org and VC++ is available at webcompiler.cloudapp.net.

Table of contents

  1. Learning Modern Core Language Features
    • Using auto whenever possible
    • Creating type aliases and alias templates
    • Understanding uniform initialization
    • Understanding the various forms of non-static member initialization
    • Controlling and querying object alignment
    • Using scoped enumerations
    • Using override and final for virtual methods
    • Using range-based for loops to iterate on a range
    • Enabling range-based for loops for custom types
    • Using explicit constructors and conversion operators to avoid implicit conversion
    • Using unnamed namespaces instead of static globals
    • Using inline namespaces for symbol versioning
    • Using structured bindings to handle multi-return values
  2. Working with Numbers and Strings
    • Converting between numeric and string types
    • Limits and other properties of numeric types
    • Generating pseudo-random numbers
    • Initializing all bits of internal state of a pseudo-random number generator
    • Using raw string literals to avoid escaping characters
    • Creating cooked user-defined literals
    • Creating raw user-defined literals
    • Creating a library of string helpers
    • Verifying the format of a string using regular expressions
    • Parsing the content of a string using regular expressions
    • Replacing the content of a string using regular expressions
    • Using string_view instead of constant string references
  3. Exploring Functions
    • Defaulted and deleted functions
    • Using lambdas with standard algorithms
    • Using generic lambdas
    • Writing a recursive lambda
    • Writing a function template with a variable number of arguments
    • Using fold expressions to simplify variadic function templates
    • Implementing higher-order functions map and fold
    • Composing functions into a higher-order function
    • Uniformly invoking anything callable
  4. Preprocessor and Compilation
    • Conditionally compiling your source code
    • Using the indirection pattern for preprocessor stringification and concatenation
    • Performing compile-time assertion checks with static_assert
    • Conditionally compiling classes and functions with enable_if
    • Selecting branches at compile time with constexpr if
    • Providing metadata to the compiler with attributes
  5. Standard Library Containers, Algorithms, and Iterators
    • Using vector as a default container
    • Using bitset for fixed-size sequences of bits
    • Using vector for variable-size sequences of bits
    • Finding elements in a range
    • Sorting a range
    • Initializing a range
    • Using set operations on a range
    • Using iterators to insert new elements in a container
    • Writing your own random access iterator
    • Container access with non-member functions
  6. General Purpose Utilities
    • Expressing time intervals with chrono::duration
    • Measuring function execution time with a standard clock
    • Generating hash values for custom types
    • Using std::any to store any value
    • Using std::optional to store optional values
    • Using std::variant as a type-safe union
    • Visiting a std::variant
    • Registering a function to be called when a program exits normally
    • Using type traits to query properties of types
    • Writing your own type traits
    • Using std::conditional to choose between types
  7. Working with Files and Streams
    • Reading and writing raw data from/to binary files
    • Reading and writing objects from/to binary files
    • Using localized settings for streams
    • Using I/O manipulators to control the output of a stream
    • Using monetary I/O manipulators
    • Using time I/O manipulators
    • Working with filesystem paths
    • Creating, copying, and deleting files and directories
    • Removing content from a file
    • Checking the properties of an existing file or directory
    • Enumerating the content of a directory
    • Finding a file
  8. Leveraging Threading and Concurrency
    • Working with threads
    • Handling exceptions from thread functions
    • Synchronizing access to shared data with mutexes and locks
    • Avoiding using recursive mutexes
    • Sending notifications between threads
    • Using promises and futures to return values from threads
    • Executing functions asynchronously
    • Using atomic types
    • Implementing parallel map and fold with threads
    • Implementing parallel map and fold with tasks
  9. Robustness and Performance
    • Using exceptions for error handling
    • Using noexcept for functions that do not throw
    • Ensuring constant correctness for a program
    • Creating compile-time constant expressions
    • Performing correct type casts
    • Using unique_ptr to uniquely own a memory resource
    • Using shared_ptr to share a memory resource
    • Implementing move semantics
  10. Implementing Patterns and Idioms
    • Avoiding repetitive if…else statements in factory patterns
    • Implementing the pimpl idiom
    • Implementing the named parameter idiom
    • Separating interfaces from implementations with the non-virtual interface idiom
    • Handling friendship with the attorney-client idiom
    • Static polymorphism with the curiously recurring template pattern
    • Implementing a thread-safe singleton
  11. Exploring Testing Frameworks
    • Getting started with Boost.Test
    • Writing and invoking tests with Boost.Test
    • Asserting with Boost.Test
    • Using test fixtures with Boost.Test
    • Controlling output with Boost.Test
    • Getting started with Google Test
    • Writing and invoking tests with Google Test
    • Asserting with Google Test
    • Using test fixtures with Google Test
    • Controlling output with Google Test
    • Getting started with Catch
    • Writing and invoking tests with Catch
    • Asserting with Catch
    • Controlling output with Catch

Credits

It took about eight months to complete this book and I got a lot of help from several people that I would like to thank to. First of all, is the team at PacktPub; although there were more people involve that I actually am aware of, I would like to thank Anurag Ghogre, Subhalaxmi Nadar and Nitin Dasan for all the help they provided throughout this time and the work they put in the project, as well as the other people that were involved with this book. I also want to thank David Corbin, whom I know for many years as “The CPU Wizard”, for reviewing the book and providing valuable feedback that made the book better. And last, but not least, I want to thank my wife for putting up with me through the many days and nights that I worked on this project.

, , , , , , , , Hits for this post: 1411 .

Initialization of variables in C++ can have several forms:

C++11 introduced a generalized syntax for initialization with a braced initializer list, referred to as braced-init-list. Initialization with braced-init-list is called list initialization. There are two types of list initialization, each having multiple forms (check the above links), but simplified, we can have:

  • direct list initialization: T object {arg1, arg2, ...};
  • copy list initialization: T object = {arg1, arg2, ...};

Prior to C++17 the type for all the following objects (a, b, c and d) is deduced to std::initializer_list<int>. There is no difference between the direct-list-initialization and the copy-list-initialization on the result of the type deduction.

This, however, changed in C++17 that introduced the following rules:

  • for copy list initialization auto deduction will deduce a std::initializer_list<T> if all elements in the list have the same type, or be ill-formed.
  • for direct list initialization auto deduction will deduce a T if the list has a single element, or be ill-formed if there is more than one element.

As a result, the example above changes so that a and c are still std::initializer_list<int> but b is deduced as an int and d is ill-formed, because there is more than one value in the brace-init-list.

For more information about these changes see N3922: New Rules for auto deduction from braced-init-list.

, , , Hits for this post: 2243 .

In C#, function parameters can be declared with the ref or out modifier, the former indicating that a value is already set and the function can read and write it, and the later that the value is not set and the function must do so before returning.

As a side note, there is a good thread on this topic on StackOverflow, What’s the difference between the ‘ref’ and ‘out’ keywords?, with one answer nailing the question in a hilarious way.

C# 7 has extended the way these modifiers can be used:

  • out variables can be declared inline and used in the outer scope
  • ref can be used for locals and return values from functions

out variables

Prior to C#7, arguments passed to out parameters had to be declared before they are used. The following is a typical example:

The new change allows the declaration of the out variable inline where it is actually used.

You can either specify an explicit type, or use the var keyword and let the compiler infer the type.
The scope of the variable declared in this manner is leaked into the output scope of the statement where it appears.

ref locals and returns

The ref modifier has been extended to be used with local variables and return values.

Local variables can be declared with the ref modifier, in which case the variable is a reference to another storage. Local references must be initialized upon declaration, and cannot be assigned values (i.e. ref var i = 42;).

On the other hand, functions can return references to variables. In this case the ref modifier needs to be used both on the return type declaration and on every return statement.

In the following example Container is an implementation of a container that internally stores an array of elements of type T. Method at() takes an argument that represents the index of an element and returns a reference to that element, or throws an exception if the index is out of bounds. The return type is declared as ref T and the return statement is return ref.

Having an instance of this Container class we can gain access to its elements in order to read or write them using the at() method. Elements can be assigned new values directly (c.at(0) = 42;) or could be bound to local variables.

There is an important difference between the last two examples:

  • var r1 = c.at(1); the value of the second element in the container is copied to the local variable r1, even though the function returned a reference. Modifying this local variable will not affect the element in the container.
  • ref var r2 = ref c.at(2); defines r2 as a reference to the third element in the container, and therefore modifying the local variable will actually modify the element in the container.

Returning a references to a local variable is not allowed (as its scope ends when the function returns, which would make the reference point to a storage that no longer exists).

You can read more about these changes in this article, What’s new in C# 7.

, , , Hits for this post: 1747 .

Matt Godbolt has announced today that the Visual C++ compiler is finally available on Compiler Explorer (https://godbolt.org/). Compiler Explorer is a website where you can write C/C++/Rust/Go/D code, compile it with various compilers and settings and see the resulted assembly code.

The version available is 1910, i.e. VC++ 2017 RTM (the exact version number is 19.10.25017.0). The following targets are available:

  • x86: x86 CL 19 2017 RTW
  • x64: x86-64 CL 19 2017 RTW
  • ARM: ARM CL 19 2017 RTW

To give it a try, I compiled the following program:

The result may look at little bit surprizing, as it totals over 5000 lines of assembly code, as oposed to gcc 7 or clang 4 that only produce 42.

, , , Hits for this post: 2720 .

Visual Studio 2017 has been officially launched today. The release notes contain a summary of all the changes available in the new version. This post is focused on the changes for C++ development.

The Visual C++ team has released a series of blog posts to document some of the new features. Here is a list of them:

Of all the changes and new features in VC++ 2017 (that are described in details in the articles mentioned above) there are several that I want to mention:

  • The C++ compiler is C++14 complete, but still lacks several C++98 and C++11 features. It also contains some features added to C++17.
  • The standard library implementation contains C++17 features including: any, optional, variant, string_view, make_from_tuple(). The complete list of improvements is available here.
  • Visual C++ 2017 runtime is compatible to the Visual C++ 2015 runtime. That means you can link to libraries build with VC++ 2015.
  • The C++ compiler version is 19.1, a minor release of the Visual C++ 2015 compiler (version 19.0). That means _MSC_VER is 1910. On the other hand, MFC and ATL are still on version 14.0 as in Visual C++ 2015. That means _MFC_VER and _ATL_VER ar both 0x0E00.
  • It is possible to open code from any folder with the Open Folder feature and get IntelliSense, navigation, building, and debugging capabilities without creating a solution and project first.
  • You can build your projects with CMake that is now supported in Visual Studio.
  • There is a built-in support for using another C++ compiler, such as Clang or GCC (mainly intended for building projects that target Android, Linux or Mac).
  • The C++ Core Checkers for enforcing the C++ Core Guidelines are now distributed with Visual Studio.
  • Installation of Visual Studio has been redesigned. Components are delivered in “workloads”, but individual components can be added or removed. For C++ there are five workloads: Universal Windows Platform development, Desktop Development with C++, Game development with C++, Mobile development with C++, and Linux development with C++.
  • Installation folder is not c:\Program Files (x86)\Microsoft Visual Studio 15.0 as with previous version, but c:\Program Files (x86)\Microsoft Visual Studio\2017\.

Here are a couple of screenshots from installing Visual Studio:

, , , Hits for this post: 3593 .

In my previous post, Dining Philosophers in C++11, I have provided an implementation for the dining philosophers problem using modern C++ features, such as threads and mutexes. However, it was noted in the comments that the implementation did not prevent the philosophers starving to death when you remove the waiting times.

An algorithm that prevents the philosophers from starving was proposed by Mani Chandy and J. Misra and is known as the Chandy/Misra solution. This is a bit different than the original problem because it requires the philosophers to communicate with each other. The algorithm, as described on Wikipedia, is the following:

  1. For every pair of philosophers contending for a resource, create a fork and give it to the philosopher with the lower ID (n for agent Pn). Each fork can either be dirty or clean. Initially, all forks are dirty.
  2. When a philosopher wants to use a set of resources (i.e. eat), said philosopher must obtain the forks from their contending neighbors. For all such forks the philosopher does not have, they send a request message.
  3. When a philosopher with a fork receives a request message, they keep the fork if it is clean, but give it up when it is dirty. If the philosopher sends the fork over, they clean the fork before doing so.
  4. After a philosopher is done eating, all their forks become dirty. If another philosopher had previously requested one of the forks, the philosopher that has just finished eating cleans the fork and sends it.

In order to implement this, we must make several changes to the solution proposed in the previous post:

  • forks and philosophers must have identifiers
  • there is an initial setup of both forks and philosophers
  • use std::condition_variable to communicate between threads
  • increase the number of philosophers

Because it has been also argued that string_view is only available in C++17 and this implementation is supposed to work in C++11, I have replaced that with std::string const&.

In this implementation, philosophers, i.e. threads, need to communicate with each other to request the forks, i.e. resources. For this, we will use a std::condition_variable, which is a synchronization primitive that enables the blocking of one or more threads until another thread notifies it. A std::condition_variable requires a std::mutex to protect access to a shared variable. The following class, sync_channel, contains both a condition variable and a mutex and provides two methods: one that waits on the condition variable, blocking the calling thread(s), and one that notifies the condition variable, unblocking all the threads that are waiting for a signal.

The table class from the previous implementation is modified: the forks are no longer defined here, but a sync_channel is used to prevent philosophers start dining until the table setup is completed. Its name has been changed to table_setup.

The fork class is no longer a wrapper for a mutex. It has an identifier, an owner, a flag to indicate whether it is dirty or clean, a mutex, and a sync_channel that enables owners to request used forks. It has two methods:

  • request() that enables a philosopher to request the fork. If the fork is dirty, it is set to clean, and the ownership is given to the philosopher that asked for it. If the fork is clean (i.e. the current owner is eating), than the philosopher that asked for it will block, waiting for it to become dirty (i.e. the current owner has finished eating).

  • done_using() a philosopher indicates that has finished eating and notifies other philosopher that is waiting for the fork that it can have it.

There are less changes to the philosopher class: it has an identifier, and there are no more waiting times to simulate eating and thinking. There are some small changes to the following methods:

  • dine(): each philosopher only starts eating after the entire table has been setup. A condition variable, from the table_setup object is used for this.

  • eat(): each philosopher first requests the left and right fork. When they are available, they are locked using std::lock() to avoid possible deadlocks, and then their ownership is transfered to a std::lock_guard object, so they are properly released when done. After eating, the fork is set as dirty and other philosophers waiting for it are notified of this.

According to the initial setup, each fork is given to the philosopher with the lower ID. That means fokm 1, placed between philosopher 1 and N, goes to philosopher 1. Fork 2, placed between philosophers 2 and 3 is given to philosopher 2. Eventually, fork N, placed between philosophers N and 1, is given to philosopher 1. Overall, this means all philosophers have initially 1 fork, except for the first one that has two, and the last philosopher, that has none.

Put all together, the code looks like this:

The output of the program looks like this:

, , , , , , Hits for this post: 5236 .

Dining Philosophers in C++11

UPDATE: for an implementation of the Chandy/Misra solution see Dining philosophers in C++11: Chandy-Misra algorithm

The problem of the dining philosophers, first proposed by Edsger Dijkstra and reformulated by Tony Hoare, is a famous problem for concurrent programming that illustrates problems with synchronizing access to data. The description of the problem, taken from Wikipedia, is the following:

Five silent philosophers sit at a round table with bowls of spaghetti. Forks are placed between each pair of adjacent philosophers.

Each philosopher must alternately think and eat. However, a philosopher can only eat spaghetti when they have both left and right forks. Each fork can be held by only one philosopher and so a philosopher can use the fork only if it is not being used by another philosopher. After an individual philosopher finishes eating, they need to put down both forks so that the forks become available to others. A philosopher can take the fork on their right or the one on their left as they become available, but cannot start eating before getting both forks.

Eating is not limited by the remaining amounts of spaghetti or stomach space; an infinite supply and an infinite demand are assumed.

The idea is to find a solution so that none of the philosophers would starve, i.e. never have the chance to acquire the forks necessary for him to eat.

Below I propose a simple implementation to this problem using C++11 language and library features. The following classes are defined:

  • fork represents a fork at the table; the only member of this structure is a std::mutex that will be locked when the philosopher picks up the fork and unlocked when he puts it down.

  • table represents the round table where the philosophers are dining. It has an array of forks, but also an atomic boolean that indicates that the table is ready for the philosophers to start thinking and eating.

  • philosopher represents a philosopher dining at the table. It has a name and a reference to the forks on his left and right.

Most of the implementation of the solution is part of the philosopher class. When an object of this class is instantiated, a thread is started. This thread is joined when the object is destroyed. The thread runs a loop of thinking and eating until the dinner is signaled to end by setting the ready member of the table to false. There are three main methods in the philosopher class:

  • dine() is the thread function; this is implemented as a simple loop of thinking and eating.

  • think() is the method that represents the thinking period. To model this the thread sleeps for a random period of time.

  • eat() is the method that models the eating. The left and right forks are acquired in a deadlock free manner using std::lock. After the forks, i.e. mutexes, are acquired, their ownership is transfered to a std::lock_guard object, so that the mutexes are correctly released when the function returns. Eating is simulated with a sleep.

To see how this works, we create a table object and an array of phylosophers. Upon creating the philosopher objects their own working thread is started, but nothing happens until the table is signaled as being ready. Philosophers then compete for the forks (i.e. mutexes), eat and think until the dinner is signaled as finished by setting the ready flag of the table object back to false.

The whole implementation is show below:

The output for this program (that varies with each execution) has the following form:

Though the problem is usually described in terms of five philosophers, any number of philoposhers can be present at the table (of course, at least two are necessary for the problem to make sense). Adding more philosophers does not require any changes in the implementation.

, , , , , , Hits for this post: 5009 .

The new Visual C++ 2017, currently in release candidate phase, provides a series of updates and fixes to both the C++ compiler and the standard library. A comprehensive list of these improvements is available at What’s New for Visual C++ in Visual Studio 2017 RC.

In this article, I want to shortly look at the new standard library features from VC++ 2017.

  • std::any (available in header <any>) is a class that represents a type-safe container that can hold the value of any copy-constructible object. To read the value stored in an any variable you need to use the non-member function std::any_cast.

  • std::optional (available in header <optional>) is a class template that may or may not contain a value any moment in time. If it contains a value, it is allocated as part of the optional object, and therefore does not incur any memory overhead.

  • std::variant (available in header <variant>) is a class template that represents a type-safe union. A variant can hold any number of alternatives, but they cannot be of type reference, array or void. The first alternative must be default constructible, because variants are default constructible and a default-constructed variant object contains a value of its first alternative. If the first alternative is not default-constructible, std::monostate (an empty, default-constructible class) can be used for that purpose. If it contains a value, it is allocated as part of the variant object, and therefore does not incur any memory overhead.

  • std::basic_string_view (available in header <string_view>) is a class template that represents a view of a contigous sequence of characters (defined by a pointer to the start of the sequence and a count). Several type aliases are available:

    basic_string_view has an interface almost identical to basic_string so that switching from the later is as simple as possible. A typical useage of this class template is for function parameters as a replacement for constant references to basic_string.

Additional new supported C++17 standard library features are:

  • std::apply is a function template that invokes a specified callable object with a tuple of arguments.
  • std::make_from_tuple is a function template that creates an object by invocking its constructor with the members of a specified tuple.

To have all these available the /std::c++latest compiler switch must be used. This can be also set from the project properties, at C/C++ > Language > C++ Language Support.
vclangsettings

, , , , , , Hits for this post: 7602 .

Last week I was in Redmond for the Microsoft MVP 2016 Summit. At the same time, the ISO C++ committee was having its fall meeting in Issaquah, which is very close to Redmond. Therefore, after the summit ended, a group of VC++ MVPs, including myself, decided to make the short trip to Issaquah and attend as observers the meetings, that are actually opened for the public. It was a very interesting experience and I am glad that I had the opportunity to take it.

The committee is organized in several working groups (WG) and study groups (SG). You can actually read all about that here. These groups have separate meetings as they are focussed on different things. I have attended a meeting of the Evolution Working Group (aka EWG), as, at that point, it looked like the most interesting of them all. These meetings actually took place in the same location where the final version of C++14 was voted.

Apart from the topics that have been discussed, which I will not elaborate on here, even though they were interesting and important, it was rather the way the committee is working that it was of most interest to me. I always had the impression that discussions were held in the fashion of the debates in the British Parliament or something similar, and I was surprised to see a much more organized, though still vocal, group. People are patiently taking turns to speak, constantly come with unexpected arguments or counter examples and eventually take polls to see what is the group’s overall opinion on the discussed topic(s). It also helped understand the process proposals go through from an initial form to the one that is eventually voted, if that is the case. I realized that it is way too easy for us to complain that things take too much time to be accepted. The reality is there are so many details that have to be taken into account and it takes many people to see them all. Everything needs to be backward compatible and it takes a lot of scrutiny and proposal iterations to reach a generally accepted form.

Overall, it was definitely a trip worth making, and I am looking forward to doing that again. I also encourage all of you that are interested in that and have the opportunity to take it.

For information about the progress in Issaquah see Herb Sutter’s Trip report: Fall ISO C++ standards meeting (Issaquah).

, , , , Hits for this post: 5529 .

DISCLAIMER: the following is a pure hypothetical list of wishes I had about C++. You should treat it as it is. This is not supposed to be a collection of community agreed list of wishes, nor it is intended to make complete sense, as some of these features are available through the standard library. Please procedure further with that in mind.

I was thinking lately what are the top language features I am missing from C++ but are available in other similar languages (such as C# or Java). After some consideration I have come up with the following list. Note that this list refers to language features only, and not library features and they are listed in a rather random order.

  • Native string type, other than char*, rather a language built-in std::string
  • Native datetime type, that would allow us to specify points of times without a built-in resolution. Obviously adding this after the chrono library makes no sense. This refers rather to a language feature that should have been available from the beginning. The reason for that is specifying date and time is a common operation we often need to do.
  • Native interfaces, other than abstract classes with pure virtual functions only as it is currently possible, because such classes can also contain data members. The reason for this is convenience in defining interface. The syntax for this should not require us to define the member functions as virtual and pure, they should be virtual implicitly. Interface member functions should also be mandatory public so we should not have to declare that either. And last, but not lease, interfaces define contracts and therefore a special interface class should not allow to define data members, not static methods.
  • Properties, basically a pair of get/set accessors over a data member. Having automatic properties to create data members and accessors would be even better. We manually write these all the time and having the compiler generate them for us would be a productivity boost.
  • Extension methods that would enable extending exiting types with new methods without modifying the type itself. This can be be achieve in different ways, but support in the language for this feature means we can extend existing code with new methods without touching it, and call these methods as they were actual member of the class.
  • Template type constraints basically what concepts will provide in the future, so I will not insist on this. Current workarounds with enable_if and SFINAE, static_assert and even deleted functions currently exist.
  • Events to enable a subject to notify observers that something has happened. Obviously this can be implemented explicitly using existing functionality, having native support for that would simplify writing code and increase productivity.
  • Switching on other types than integral types, especially on strings. In general it should be possible to switch on any compile time constant expression. The reason for this is to replace if-else statements with a simpler to write and read switch statement.
  • Finally block for a try-catch so we can specify code that should execute regardless of whether an exception occurs or not. This is supposed be achieved by implementing the RAII idiom. Resources should be released properly upon destruction, but the reality is that a lot of code does not use RAII. Having finally blocks would enable us to run clean up code either if an exception occurred or not.
  • Static classes, that can contain only static members, and static constructors, that are called before main and have access only to static members of a class (there is actually a proposal for static constructors under discussion for standardization). Helper functions may be implemented as static members of a class, and having the class as static would be a constraint on the class to only contain static members.

I do known and understand the principles of C++ and I know these may look counter intuitive. I know why string is a library container, and why time points are available through a library and why these are general purpose implementations intended to meet many needs. For instance the chrono library is resolution agnostic, which means that in the future clocks will deliver picosecond resolution we won’t need to update the library to benefit from that.

On the other hand the reality is that general purpose implementations lack many features developers use all the time, such as converting a string to upper or lower case. This is available in many languages or string libraries, but not in the standard library string. Yes, we can implement that simply in a helper function, but if extension methods were available we could call such a helper function as it was a member of the string class, which would look, arguably, more natural, and also similar to what is available in other languages.

Another reality is that many developers use more than just one language. Some of these features would enable developers coming from a background of .NET or Java development to get a faster and better grasp at C++.

The most important benefits of these feature would be less and probably more readable code and an increased productivity. There are workarounds for these and, yes, we can live without them. But I do not believe that makes at least some of them unreasonable.

I would like to hear what are the features that you miss the most and see if they also appear on this list.

, , , Hits for this post: 6940 .