C++: Strategy Pattern vs. Policy Based Design

Strategy Pattern

In object-oriented programming languages like Java or C#, there is the very popular Strategy Pattern.

The Strategy Pattern consists of injecting “strategies” into a class that will consume them. These “strategies” are classes that provide a set of methods with a specific behavior that the consuming class needs. The purpose of this pattern is to offer versatility by allowing these behaviors to be modified, extended, or replaced without changing the class that consumes them. To achieve this, the consumer is composed of interfaces that define the behavior to be consumed, and at some point (typically during instantiation), the infrastructure injects concrete implementations of these interfaces into the consumer.

This is the example that will be used in this post: A store needs a product provider and a stock provider to gather all the information it requires.

Using the Strategy Pattern, the class diagram for the example is shown below:

In C++ the implementation of this pattern is similar to the one described here: The “interfaces” (implemented as Abstract Base Classes in C++) IProductProvider and IStockProvider and their data classes and structs will be declared as follows:

struct Product
{
    std::string id;
    std::string name;
    std::string brand;
};

class IProductProvider
{
public:
    virtual ~IProductProvider() = default;
    
    virtual std::shared_ptr<Product> get_product_by_id(const std::string& id) const = 0;
    virtual std::vector<std::string> get_all_product_ids() const = 0;
};

struct Stock final
{
    std::string product_id;
    int count;
};

class IStockProvider
{
public:
    virtual ~IStockProvider() = default;
    
    virtual int get_stock_count_by_product_id(const std::string& id) const = 0;
};

Now, the following code shows the service class that uses both providers, implementing the Strategy Pattern:

struct ProductAndStock final
{
    std::shared_ptr<Product> product;
    int stock_count;
};

class Store
{
    std::unique_ptr<IProductProvider> _product_provider;
    std::unique_ptr<IStockProvider> _stock_provider;
    
public:
    Store(
        std::unique_ptr<IProductProvider> product_provider, 
        std::unique_ptr<IStockProvider> stock_provider)
    : _product_provider{std::move(product_provider)}
    , _stock_provider{std::move(stock_provider)}
    {
    }
    
    std::vector<ProductAndStock> get_all_products_in_stock() const
    {
        std::vector<ProductAndStock> result;
        
        for (const auto& id : _product_provider->get_all_product_ids())
        {
            // We will not load products that are not in stock
            const auto count = _stock_provider->get_stock_count_by_product_id(id);
            if (count == 0)
                continue;
                
            result.push_back({_product_provider->get_product_by_id(id), count});
        }
        
        return result;
    }
};

Assuming the product and stock information is available in a database, programmers can implement both interfaces and instantiate the Store like this::

Store store{
        std::make_unique<DBProductProvider>(), 
        std::make_unique<DBStockProvider>()};

In the declaration above, it is assumed that DBProductProvider and DBStockProvider are derived from IProductProvider and IStockProvider, respectively, and that they implement all the pure virtual methods declared in their base classes. These methods should contain code that accesses the database, retrieves the information, and maps it to the data types specified in the interfaces.

Pros:

  1. The Store class is completely agnostic about how the data is retrieved, which means low coupling.
  2. Due to the reason above, the classes can be replaced with other ones very easily, and there is no need to modify anything in the Store.
  3. For the same reason, this makes creating unit tests very easy because creating MockProductProvider and MockStoreProvider classes is actually trivial.

Cons:

Not a “severe” negative point, but because everything is virtual here, polymorphism takes a little extra time for the actual bindings at runtime.

Alternative to Strategy Pattern: Policy-Based Design

Policy-Based Design is an idiom in C++ that solves the same problem as the Strategy Pattern, but in a C++ way, i.e., with templates ;)

Policy-Based Design involves having the consumer class as a class template, where the “Policies” (what was called “Strategy” in the Strategy Pattern) are part of the parameterized classes in the template definition.

The example above would look like this with Policy-Based Design:

struct Product
{
    std::string id;
    std::string name;
    std::string brand;
};

struct Stock final
{
    std::string product_id;
    int count;
};

struct ProductAndStock final
{
    std::shared_ptr<Product> product;
    int stock_count;
};

template <
    typename ProductProviderPolicy,
    typename StockProviderPolicy>
class Store
{
    ProductProviderPolicy _product_provider;
    StockProviderPolicy _stock_provider;
    
public:
    Store() = default;
    
    std::vector<ProductAndStock> get_all_products_in_stock() const
    {
        std::vector<ProductAndStock> result;
        
        for (const auto& id : _product_provider.get_all_product_ids())
        {
            // We will not load products that are not in stock
            const auto count = _stock_provider.get_stock_count_by_product_id(id);
            if (count == 0)
                continue;
                
            result.push_back({_product_provider.get_product_by_id(id), count});
        }
        
        return result;
    }
};

To use it:

Store<DBProductProvider, DBStockProvider> store;

Pros:

  1. Better performance because all bindings are performed by the compiler, which creates a very optimized piece of code by knowing all the code in advance. Notice even that the _product_provider and _stock_provider instances are not even pointers!
  2. Classes are still replaceable with other implementations, though not at runtime.
  3. It is also easy to create unit tests with this approach.

Cons:

  1. In my very specific example, no IProductProvider or IStockProvider are defined because of the nature of templates. So the methods that need to be implemented must be documented somewhere. BUT, that can be solved through C++ Concepts, right? Thanks to C++ Concepts the validation that the providers implement all methods needed is done in compile time.

Something like this:

template <typename T>
concept TProductProvider = 
    requires(T t, const std::string& id) {
        { t.get_product_by_id(id) } -> std::same_as<std::shared_ptr<Product>>;
        { t.get_all_product_ids() } -> std::same_as<std::vector<std::string>>;
    };
    
template <typename T>
concept TStockProvider =
    requires(T t, const std::string& id) {
        { t.get_stock_count_by_product_id(id) } -> std::same_as<int>;
    };

and then declare the Store as follows:

template <
    TProductProvider ProductProviderPolicy, 
    TStockProvider StockProviderPolicy>
class Store
{
    ProductProviderPolicy _product_provider;
    StockProviderPolicy _stock_provider;
    
public:
    Store() = default;
    
    std::vector<ProductAndStock> get_all_products_in_stock() const
    {
        std::vector<ProductAndStock> result;
        
        for (const auto& id : _product_provider.get_all_product_ids())
        {
            // We will not load products that are not in stock
            const auto count = _stock_provider.get_stock_count_by_product_id(id);
            if (count == 0)
                continue;
                
            result.push_back({_product_provider.get_product_by_id(id), count});
        }
        
        return result;
    }
};

The static nature of this idiom makes it not a completely general solution, but it can cover, speculatively, a large percentage of cases. Sometimes, programmers think in dynamic solutions to solve problems that do not require such dynamism.

C++: std::monostate

std::monostate was released with std::variant in C++17.

Essentially, std::monostate is a type where all its instances have exactly the same (and empty) state, hence its name.

Think of its implementation as being similar to something like this:

class empty { };

And what is it useful for?

  1. An instance of this class can be used to represent the initial value of a std::variant when declared as its first type. A std::variant MUST always contain a valid value, so std::monostate is quite useful when its initial value is not known a priori or when the other data types do not have default constructors.
std::variant<std::monostate, int, std::string> value; // here value is instantiated using std::monostate.
  1. It can be used when representing a “no-value” as a valid std::variant value is needed.
std::variant<int, std::string, std::monostate> value{2}; // stores an int.
value = std::monostate{}; // now stores a new instance of std::monostate.
  1. Independently from std::variant, it can be used when a class with no data is required. A concrete example?

Currently, I am working on a UI layout system. The layout_container can store UI widgets and, depending on the layout policies used, they need to specify a “constraint.” The constraint could be a relative XY coordinate, or a position inside a border_layout (north, south, etc.) or NOTHING (for example, in a flow-based layout, the UI controls are positioned one next to the other, flowing like text, and thus, they do not need any constraint).

So I could define my layout_container like this:

template <typename Constraint, typename LayoutPolicy>
class layout_container;

and have the specific types like:

using border_layout_container = layout_container<border_layout_constraint, border_layout_policy>;
using xy_layout_container = layout_container<xy_layout_constraint, xy_layout_policy>;
using flow_layout_container = layout_container<std::monostate, flow_layout_policy>;

I do not need to change anything in my layout_container to support (or not) constraints thanks to std::monostate.

  1. Additionally, std::monostate implements all comparison operators (operator==, operator!=, etc.). All instances are equal, by the way. Finally, std::monostate can also be used as a key on std::unordered_map instances because it provides a specialization for std::hash.

Want to read more about std::variant? Check this out!

C++: [[maybe_unused]

When you declare a function or a method with an argument that will not be used, the compiler emits a warning (if -Wunused-parameter is enabled in gcc and clang) about that issue.

See the code below:

#include <iostream>
#include <string>

void print_msg(const std::string& e)
{
  std::cout << "Hello world\n";
}

int main()
{
  print_msg("Friday");
  return 0;
}

The g++ compiler output is;

In function 'void print_msg(const std::string&)':
<source>:4:35: warning: unused parameter 'e' [-Wunused-parameter]
    4 | void print_msg(const std::string& e)
      |                ~~~~~~~~~~~~~~~~~~~^

It is a good idea to enable this compiler flag (-Wunused-parameter) to remove all unused parameters from your code, making it cleaner.

That could mean removing the parameter completely like below:

void print_msg();

or simply removing the variable name from the argument list:

void print_msg(const std::string& );

Why would you choose the latter instead of the former?

  1. You are sure you will use that parameter later, so you prefer keeping it to avoid modifying all the places where your function is called.
  2. You are overriding a method where the parameter is not used and you cannot modify the interface of the virtual method you are implementing.
  3. You want to catch an exception but do not want to do anything with the exception itself (probably you want to ignore the exception, log a message, or generate a more generic error code).

However, in some scenarios, you simply do not know if a variable will be used or not (e.g. conditional compilation based on #define and #ifdef preprocessor directives or template-based code).

Consider this example:

You have a log subsystem but want to enable it with the LOG_ENABLED preprocessor definition. This is its implementation:

void log_msg(const std::string& msg)
{
#ifdef LOG_ENABLED    
    std::cout << msg << "\n";
#else
    // do nothing
#endif
}

int main()
{
  log_msg("This is a something to log");
}

If the LOG_ENABLED definition is set, everything will work as expected, otherwise the “unused parameter” warning will occur.

Since it is a good idea to enable such warnings AND it is also a good idea to have your code as clean and expressive as possible, [[maybe_unused]] is the hero here.

[[maybe_unused]] is an attribute introduced in C++17 that is used to mark structs, classes, variables, arguments, enums, etc. as “probably unused”, so the compiler simply ignores if such symbols are not being used in the scope they are defined. Thus, apart from removing the warning, marking a variable as “maybe unused” is a nice way to self-document the code and the intentions behind the symbols you create.

Your program will look like this with this attribute:

#include <iostream>
#include <string>


void log_msg([[maybe_unused]] const std::string& msg)
{
#ifdef LOG_ENABLED    
    std::cout << msg << "\n";
#else
    // do nothing
#endif
}

int main()
{
  log_msg("This is a something to log");
}

More on this attribute here: https://en.cppreference.com/w/cpp/language/attributes/maybe_unused

RAII

What is RAII?

RAII stands for ‘Resource Acquisition Is Initialization.’ It is arguably one of the most elegant and useful features that C++ has introduced to the world. Both D and Rust have incorporated it into their specifications as well.

What does it mean?

RAII, “obviously,” means that any entity requesting a resource from the system (memory, file handle, network connection, etc.) should be responsible for releasing that resource when its lifetime has ended.

In C++ jargon, this means that any resource needed by an object must be acquired by the object’s constructor and released in its destructor.

Thanks to this very interesting feature, when a variable representing an object created with value semantics goes out of scope, its destructor is invoked automatically and seamlessly, releasing any resources the object may have acquired during its lifetime.

That solves many resource-related issues in a very transparent way when the variables go out of scope:

  • Any dynamically allocated memory owned by this object can be released.
  • Any open file handle can be closed.
  • Any network connection can be closed.
  • Any database connection can be closed.
  • Any registry handle can be released.
  • Any mutex can be unlocked.

… and so on.

The best part is that, while several languages offer garbage collectors limited to handling memory, RAII provides a cleaner alternative for managing not only memory but any type of resources.

Now, let’s see how it can be used.

First, let’s look at how these constructors and destructors are invoked:

#include <iostream>

class A final
{
    int n;

public:
    explicit A(int n) : n{n} { std::cout << "Hello " << n << std::endl; }
    ~A() { std::cout << "Bye " << n << std::endl; }
};

void test()
{
    A a{1};
    A b{2};
    A c{3};
}

int main()
{
    std::cout << "Begin" << std::endl;
    test();
    std::cout << "End" << std::endl;
}

When running this, the output will be:

Begin
Hello 1
Hello 2
Hello 3
Bye 3
Bye 2
Bye 1
End

Two things can be noticed here:

  1. The destructors are invoked automatically before exiting the test function. Why is that? Because a, b, and c were created in that code block.
  2. The order of destructor calls is the reverse of their creation order.

Since the destructors are invoked automatically, they can leverage this interesting feature (RAII) to free any resources acquired by their code. For example, they could modify class A to store that int value on the heap instead (which is a bad idea, by the way):

class A final
{
    int* pn;

public:
    explicit A(int n) 
    : pn{new int{n}} 
    {
        std::cout << "Hello " << *pn << std::endl; 
    }

    ~A()
    { 
        std::cout << "Bye " << *pn << std::endl; 
        delete pn;
    }
};

Note that resources are acquired in the constructor and released in the destructor.

In this way, the user of class A does not need to worry about the resources it uses.

“Out of scope” also means that if the function ends abruptly or returns prematurely, it will be guaranteed that the destructors of the objects are invoked before control is transferred back to the caller.

This will be tested by adding an exception:

#include <iostream>

class A final
{
    int* pn;

public:
    explicit A(int n) 
    : pn{new int{n}} 
    {
        std::cout << "Hello " << *pn << std::endl; 
    }

    ~A()
    { 
        std::cout << "Bye " << *pn << std::endl; 
        delete pn;
    }
};

void test(int nonzero)
{
    A a{1};
    A b{2};

    if (nonzero == 0)
        throw "Arg cannot be zero";

    A c{3};
}

int main()
{
    std::cout << "Begin" << std::endl;
    try
    {
        test(0);
    }
    catch (const char* e)
    {
        std::cout << e << std::endl;
    }
    std::cout << "End" << std::endl;
}

Note that an exception is thrown after objects a and b are created. When the exception occurs, the function test ends abruptly, but the destructors of a and b will be invoked before entering the catch block.

The destructor of object c is not invoked because the object was not created when the exception occurred.

The same behavior occurs if a function is exited prematurely.

Now, look at class B that has been added to the example:

#include <iostream>

class A final
{
    int* pn;
public:
    explicit A(int n) 
    : pn{new int{n}} 
    {
        std::cout << "Hello " << *pn << std::endl; 
    }

    ~A()
    { 
        std::cout << "Bye " << *pn << std::endl; 
        delete pn;
    }
};

class B final
{
    A a;
    A b;
    
public:
    B(int valueA, int valueB) : a{valueA}, b{valueB} { }
};

void test()
{
    B a { 4, 5};
    B b { 6, 7};
}

int main()
{
    std::cout << "Begin" << std::endl;
    test();
    std::cout << "End" << std::endl;
}

The output is:

Begin
Hello 4
Hello 5
Hello 6
Hello 7
Bye 7
Bye 6
Bye 5
Bye 4
End

Why are the destructors of A called when B objects go out of scope if a destructor for B was not written?

Because when a destructor is not defined, one is automatically generated by the compiler that invokes the destructors of all member variables with value semantics.

Thus, if basic classes handle resources explicitly, the likelihood of needing to acquire or release resources explicitly in constructors or destructors is actually low.

What about pointers?

RAII does not work with raw pointers, so if something like this is declared in a function:

int* array = new int[1024];

nothing will happen when that variable array goes out of scope.

Is there any way to have pointers handled by RAII?

YES! Through smart pointers!

Other non-memory related uses?

  • std::ifstream and std::ofstream close automatically the file they opened to be read or written.
  • std::lock_guard<T> locks a mutex in its constructor and unlocks it in its destructor, avoiding threads locked by mistake.
  • If UI is being written, a MouseRestorer could be needed that automatically sets the mouse to its default value after it has been changed to an hourglass during a time-consuming piece of code.

C++17: std::any

When trying to implement something that will store a value of an unknown data type (to be as generic as possible, for example), we had these possibilities before C++17:

  • Having a void* pointer to something that will be assigned at runtime. The problem with this approach is that it leaves all responsibility for managing the lifetime of the data pointed to by this void pointer to the programmer. Very error prone.
  • Having a union with a limited set of data types available. We can use still use this approach using C++17 variant.
  • Having a base class (e.g. Object) and store pointers to instances derived of that class (à la Java).
  • Having an instance of template typename T (for example). Nice approach, but to make it useful and generic, we need to propagate the typename T throughout the generic code that will use ours. Probably verbose.

So, let’s welcome to std::any.

std::any, as you already guess it, is a class shipped in C++17 and implemented in header <any> that can store a value of any type, so, these lines are completely valid:

std::any a = 123;
std::any b = "Hello";
std::any c = std::vector<int>{10, 20, 30};

Obviously, this is C++ and you as user need to know the data type of what you stored in an instance of std::any, so, to retrieve the stored value you have to use std::any_cast<T> as in this code:

#include <any>
#include <iostream>

int main()
{
    std::any number = 150;
    std::cout << std::any_cast<int>(number) << "\n";
}   

If you try to cast the value stored in an instance of std::any to anything but the actual type, a std::bad_any_cast exception is thrown. For example, if you try to cast that number to a string, you will get this runtime error:

terminate called after throwing an instance of 'std::bad_any_cast'
  what():  bad any_cast

If the value stored in an instance of std::any is an instance of a class or struct, the compiler will ensure that the destructor for that value will be invoked when the instance of std::any goes of scope.

Another really nice thing about std::any is that you can replace the existing value stored in an instance of it, with another value of any other type, for example:

std::any content = 125;
std::cout << std::any_cast<int>(content) << "\n";

content = std::string{"Hello world"};
std::cout << std::any_cast<std::string>(content) << "\n";

About lifetimes

Let’s consider this class:

struct A
{
  int n;
  A(int n) : n{n} { std::cout << "Constructor\n"; }
  ~A() { std::cout << "Destructor\n"; }
  A(A&& a) : n{a.n} { std::cout << "Move constructor\n"; }
  A(const A& a) : n{a.n} { std::cout << "Copy constructor\n"; }
  void print() const { std::cout << n << "\n"; }
};

This class stores an int, and prints it out with “print”. I wrote constructor, copy constructor, move constructor and destructor with logs telling me when the object will be created, copied, moved or destroyed.

So, let’s create a std::any instance with an instance of this class:

std::any some = A{4516};

This will be the output of such code:

Constructor
Move constructor
Destructor
Destructor

Why two constructors and two destructors are invoked if I only created one instance?

Because the instance of std::any will store a copy (ok, in this case a “moved version”) of the original object I created, and while in my example it may be trivial, in a complex object it cannot be.

How to avoid this problem?

Using std::make_any.

std::make_any is very similar to std::make_shared in the way it will take care of creating the object instead of copying/moving ours. The parameters passed to std::make_any are the ones you would pass to the object’s constructor.

So, I can modify my code to this:

auto some = std::make_any<A>(4517);

And the output will be:

Constructor
Destructor

Now, I want to invoke to the method “print”:

auto some = std::make_any<A>(4517);
std::any_cast<A>(some).print();

And when I do that, the output is:

Constructor
Copy constructor
4517
Destructor
Destructor

Why such extra copy was created?

Because std::any_cast<A> returns a copy of the given object. If I want to avoid a copy and use a reference, I need to explicit a reference in std::any_cast, something like:

auto some = std::make_any<A>(4517);
std::any_cast<A&>(some).print();

And the output will be:

Constructor
4517
Destructor

It is also possible to use std::any_cast<T> passing a pointer to an instance of std::any instead of a reference.

In such case, if the cast is possible, will return a valid pointer to a T* object, otherwise it will return a nullptr. For example:

auto some = std::make_any(4517);
std::any_cast<A>(&some)->print();
std::cout << std::any_cast<int>(&some) << "\n";

In this case, notice that I am passing a pointer to “some” instead of a reference. When this occurs, the implementation returns a pointer to the target type if the stored object is of the same data type (as in the second line) or a null pointer if not (as in the third line, where I am trying to cast my object from type A to int). Using this version overloaded version with pointers avoids throwing an exception and allows you to check if the returned pointer is null.

std::any is a very good tool for storing things that we, as implementers of something reusable, do not know a priori; it could be used to store, for example, additional parameters passed to threads, objects of any type stored as extra information in UI widgets (similar to the Tag property in Windows.Forms.Control in .NET, for example), etc.

Performance wise, std::any needs to store stuff in the heap (this assert is not completely correct: Where the stuff is actually stored depends on the actual library implementation and some of them [gcc’s standard library] store locally elements whose sizeof is small [thanks TheFlameFire]) and also needs to do some extra verification to return the values only if the cast is valid, so, it is not as fast as having a generic object known at compile time.

C++20: Concepts, an introduction

I am pretty new doing C++ Concepts, so I will post here the things I will learn while starting to use them.

C++ Concepts are one of these three large features that are shipped with C++20:

  • Concepts
  • Ranges
  • Modules

Basically, C++ Concepts define a set of conditions or constraints that a data type must fulfill in order to be used as a template argument.

For example, I would want to create a function that sums two values and prints the result. In C++17 and older I would code something like this:

template <typename A, typename B>
void sum_and_print(const A& a, const B& b)
{
    std::cout << (a + b) << "\n";
}

And it works properly for types A and B that DO have the operator+ available. If the types I am using do not have operator+, the compiler naïvely will try to substitute types A and B for the actual types and when trying to use the missing operator on them, it will fail miserably.

The way the compiler works is correct, but failing while doing the actual substitution with no earlier verification is kind of a reactive behavior instead of a proactive one. And in this way, the error messages because of substitution error occurrences are pretty large, hard to read and understand.

C++20 Concepts provide a mechanism to explicit the requirements that, in my example, types A and B would need to implement in order to be allowed to use the “sum_and_print” function template. So when available, the compiler will check that those requirements are fulfilled BEFORE starting the actual substitution.

So, let’s start with the obvious one: I will code a concept that mandates that all types that will honor it will have operator+ implemented. It is defined in this way:

template <typename T, typename U = T>
concept Sumable =
 requires(T a, U b)
 {
    { a + b };
    { b + a };
 };

The new keyword concept is used to define a C++ Concept. It is defined as a template because the concept will be evaluated against the type or types that are used as template arguments here (in my case, T and U).

I named my concept “Sumable” and after the “=” sign, the compiler expects a predicate that needs to be evaluated on compile time. For example, if I would want to create a concept to restrict the types to be only “int” or “double”, I could define it as:

template <typename T>
concept SumableOnlyForIntsAndDoubles = std::is_same<T, int>::value || std::is_same<T. double>::value;

The type trait “std::is_same<T, U>” can be used here to create the constraint.

Back to my first example, I need that operator+ will be implemented in types A and B, so I need to specify a set of requirements for that constraint. The new keyword “requires” is used for that purpose.

So, any definition between braces in the requires block (actually “requires” is always a block, even when only a requirement is specified) is something the types being evaluated must fulfill. In my case, “a+b” and “b+a” must be valid operations. If types T or U do not implement operator+, the requirements will not be fulfilled and thus, the compiler will stop before even trying to substitute A and B for actual types.

So, with such implementation, my function “sum_and_print” works like a charm for ints, doubles, floats and strings!

But, what if I have another type like this one:

struct N
{
    int value;

    N operator+(const N& n) const
    {
        return { value + n.value };
    }
};

Though it implements operator+, it does not implement operator<< needed to work with std::cout.

To add such constraint, I need to add an extra requirement to my concept. So, it could be like this one:

template <typename T, typename U = T>
concept Sumable =
 requires(T a, U b)
 {
    { a + b };
    { b + a };
 }
 && requires(std::ostream& os, const T& a)
 {
     { os << a };
 };

The operator && is used here to specify that those requirements need to be fulfilled: Having operator+ AND being able to do “os << a“.

If my types do not fulfill such requirements, I get an error like this in gcc:

<source>:16:5:   in requirements with 'std::ostream& os', 'const T& a' [with T = N]
<source>:18:11: note: the required expression '(os << a)' is invalid
   18 |      { os << a };
      |        ~~~^~~~

That, though looks complicated, is far easier to read than the messages that the compiler produces when type substitution errors occur.

So, if I want to have my code working properly, I need to add an operator<< overloaded for my type N, having finally something like this:

#include <iostream>

template <typename T, typename U = T>
concept Sumable =
 requires(T a, U b)
 {
    { a + b };
    { b + a };
 }
 && requires(std::ostream& os, const T& a)
 {
     { os << a };
 };

template <Sumable A, Sumable B>
void sum_and_print(const A& a, const B& b)
{
    std::cout << (a + b) << "\n";
}

struct N
{
    int value;

    N operator+(const N& n) const
    {
        return { value + n.value };
    }
};

std::ostream& operator<<(std::ostream& os, const N& n)
{
    os << n.value;
    return os;
}

int main()
{
    sum_and_print( N{6}, N{7});
}

Notice that in my “sum_and_print” function template I am writing “template <Sumable a, Sumable b>” instead of the former “template <typename A, typename B>“. This is the way I ask the compiler to validate such type arguments against the “Sumable” concept.


What if I would want to have several “greeters” implemented in several languages and a function “greet” that will use my greeter to say “hi”. Something like this:

template <Greeter G>
void greet(G greeter)
{
    greeter.say_hi();
}

As you can see, I want my greeters to have a method “say_hi“. Thus, the concept could be defined like this one in order to mandate the type G to have the method say_hi() implemented:

template <typename G>
concept Greeter = requires(G g)
{
    { g.say_hi() } -> std::convertible_to<void>;
};

With such concept in place, my implementation would be like this one:

template <typename G>
concept Greeter = requires(G g)
{
    { g.say_hi() } -> std::convertible_to<void>;
};

struct spanish_greeter
{
    void say_hi() { std::cout << "Hola amigos\n"; }
};

struct english_greeter
{
    void say_hi() { std::cout << "Hello my friends\n"; }
};


template <Greeter G>
void greet(G greeter)
{
    greeter.say_hi();
}


int main()
{
    greet(spanish_greeter{});
    greet(english_greeter{});
}

Why would I want to use concepts instead of, say, base classes? Because:

  1. While using concepts, you do not need to use base classes, inheritance, virtual and pure virtual methods and all that OO stuff only to fulfill a contract on probably unrelated stuff, you simply need to fulfill the requirements the concept defines and that’s it (Interface Segregation of SOLID principles would work nice here, anyway, where your concepts define the minimum needed possible constraints for your types).
  2. Concepts are a “Zero-cost abstraction” because their validation is performed completely at compile-time, and, if properly verified and accepted, the compiler does not generate any code related to this verification, contrary to the runtime overhead needed to run virtual things in an object-oriented approach. This means: Smaller binaries, smaller memory print and better performance!

I tested this stuff using gcc 10.2 and it works like a charm.

C++ “Hello world”

Ok, the most famous first program in any programming language is the ‘Hello World’ program, so I will explain how to create one in this post.

For my example, I will use ‘g++’ in a Linux environment, but ‘clang++’ works exactly the same way.

To write a ‘Hello World’ program in C++, you will need to create an empty file and name it with an appropriate extension (any name will do, for instance, HelloWorld.cpp). Common C++ file extensions include ‘.cpp’, ‘.cxx’, and ‘.cc’.

The compiler does not require the filename to match the name of any ‘class’ or other content inside the file. You can also store the file in any folder; there is no need to create it in a specific directory containing all the elements of a ‘package’ (like in Java).

Once you have created an empty HelloWorld.cpp file, you can open it in any text editor and start writing the following lines of code:

#include <iostream>
 
int main()
{
  std::cout << "Hello world\n";
}

Save the file, open a terminal, navigate to the folder where your file is located, and then enter the following command:

g++ HelloWorld.cpp -o HelloWorld

If you do not receive any messages after entering the command, congratulations! Your program has compiled successfully. Otherwise, there is an error in your code that you will need to fix before compiling again.

Once it compiles correctly, you will need to run the program. In a Linux/Unix environment, you do this by typing ./ followed by the program’s name:

./HelloWorld

And the program output should be:

Hello world

Understanding how all of this works

The C++ compilation process consists of three main steps:

  • Preprocessing: This step involves the preprocessor, which performs various text substitutions and transformations on your code before it is compiled.
  • Compilation: During this phase, your code is converted into machine code, with placeholders for calls to functions that reside in external libraries.
  • Linking: This step resolves those function calls by linking them to the actual functions in the libraries your program uses. If you do not specify any additional libraries (as in our example), your program will only be linked to the Standard Library, which comes with any C++ compiler.

#include

#include <iostream>

All lines starting with ‘#’ are called ‘preprocessor directives’. These are instructions that the preprocessor recognizes and executes.

#include tells the preprocessor to locate the file specified either inside quotes or between angle brackets and insert its content where the #include directive is used.

If the filename is enclosed in angle brackets (as in our case), the preprocessor searches for the file in a predefined directory that the compiler is aware of. For example, it will look for the file iostream in that directory. In a Linux environment, these files are typically located in a path similar to this one (I am using g++ 8.2):

/usr/include/c++/8

If the filename is declared between double quotes, it means the file will be in the current folder or in a folder explicitly specified when compiling the program.

iostream is the file that contains a lot of code allowing our programs to handle input and output. In our ‘Hello World’, we will need std::cout, which is defined in this file.

main function

int main()

When you invoke your program, the operating system needs to know which piece of code to execute. This code resides in the main function.

All functions must return something. For example, if you call a function sum that adds two numbers, it must return a value containing the result of the sum. So, the sum function must return an integer value (an int). Some old compilers allowed the main() function to return void (meaning ‘return nothing’), but the C++ standard specifies that main() must return an int value.

However, even if main() is declared to return an int, if you do not explicitly return anything, the compiler will not complain and will automatically return 0. Note that this behavior is exceptional and only allowed for the main() function.

The return value of the main() function indicates whether an error occurred. A return value of 0 means the program executed without errors, while a non-zero value indicates an error. The specific non-zero value depends entirely on the programmer’s design and error-handling mechanisms.

The program will continue running as long as the main() function is executing. Once its execution ends, the program terminates and returns the value to the operating system.

The body of any function is enclosed in curly braces.

std::cout

std::cout << "Hello world\n";

std::cout is a pre-existing object that represents command line output. The << operator essentially sends the text "Hello world\n" to the std::cout object, resulting in that text being displayed in the terminal.

The \n character sequence indicates a newline.

g++

g++ and clang are the most popular C++ compilers for Unix platforms today. You can replace one with the other almost without restrictions because clang was designed to be a drop-in replacement for g++.

When you say something like:

g++ HelloWorld.cpp

You are instructing the g++ compiler to go through the entire compilation process for the file HelloWorld.cpp. ‘Go through the entire compilation process’ in this case means running the preprocessor on the file, compiling it, linking it, and producing an executable.

Since I did not specify the name of the executable file in the command line example above, the g++ command generates a file called a.out in the current folder.

To specify the name of the file to be generated, you must invoke g++ with the -o option followed by the name of the executable file you want to create.

C++: “auto” return type deduction

Before C++14, when implementing a function template, programmers did not know the return type of their functions and had to do something like this:

template <typename A, typename B>
auto do_something(const A& a, const B& b) -> decltype(a.do_something(b))
{
  return a.do_something(b);
}

Programmers had to use decltype to tell the compiler: “The return type of this method is the return type of the do_something method of object a.” The auto keyword was used to inform the compiler: “The return type of this function is declared at the end.”

Since C++14, coders can do something much simpler:

template <typename A, typename B>
auto do_something(const A& a, const B& b)
{
  return a.do_something(b);
}

Starting with C++14, the compiler deduces the return type of functions that use auto as the return type.

Restrictions:

All returned values must be of the same type. The example below will not even compile because it can return either an int or a double:

auto f(int n)
{
	if (n == 1)
    {
		return 1;
    }

	return 2.0;
}

For recursive functions, the first return value must allow the compiler to deduce the return type of the function, as in this example:

auto accumulator(int n)
{
	if (n == 0)
    {
		return 0;
    }

	return n + accumulator(n - 1);
}

Starting with C++20, a function can be declared like this and it will work properly:

auto do_something(const auto& a, const auto& b)
{
    return a.do_something(b);
}

When programmers define functions this way, if one or more function parameters are declared as auto, the entire function is treated as a template. So, while this new construction might seem to add more “functionality” to the auto keyword, it is really just a more convenient way of declaring function templates.

More posts about auto:

C++: Perfect forwarding

The following function template invoke (as its name says) invokes the function/functor/lambda expression passed as an argument, passing it the two extra arguments given:

#include <iostream>
#include <string>
  
void sum(int a, int b)
{
    std::cout << a + b << std::endl;
}
 
void concat(const std::string& a, const std::string& b)
{
    std::cout << a + b << std::endl;
}
 
template <typename PROC, typename A, typename B>
void invoke(PROC p, const A& a, const B& b)
{
    p(a, b);
}
 
int main()
{
    invoke(sum, 10, 20);
    invoke(concat, "Hello ", "world");
    return 0;
}

Nice, it works as expected, and the result is:

30
Hello world

The problem with that implementation is that it only works with arguments passed as constant references, so if the programmers try to invoke the following function:

void successor(int a, int& b)
{
    b = a + 1;
}

with this call:

int s = 0;
invoke(successor, 10, s);
std::cout << s << std::endl;

the compiler returns this error in the invoke implementation:

Binding of reference to type 'int' to a value of type 'const int' drops qualifiers

This error occurs because the second argument of the successor function is not a const-reference.

Before C++11, the only way to deal with this problem was creating a set of overloads containing all the possible combinations of const, non-const references in the methods, something like this:

#include <iostream>
#include <string>
 
void sum(int a, int b)
{
    std::cout << a + b << std::endl;
}
 
void concat(const std::string& a, const std::string& b)
{
    std::cout << a + b << std::endl;
}
 
void successor(int a, int& b)
{
    b = ++a;
}
 
template <typename PROC, typename A, typename B>
void invoke(PROC p, const A& a, const B& b)
{
    p(a, b);
}
 
template <typename PROC, typename A, typename B>
void invoke(PROC p, const A& a, B& b)
{
    p(a, b);
}
 
template <typename PROC, typename A, typename B>
void invoke(PROC p, A& a, const B& b)
{
    p(a, b);
}
 
template <typename PROC, typename A, typename B>
void invoke(PROC p, A& a, B& b)
{
    p(a, b);
}
 
int main()
{
    invoke(sum, 10, 20);
    invoke(concat, "Hello", "world");
    int s = 0;
    invoke(successor, 10, s);
    std::cout << s << std::endl;
    return 0;
}

Notice that there are four overloads for the invoke function template example above because two parameters need to be forwarded to the function passed in P.

If the function had more parameters, this would be unmaintainable (for N arguments, programmers would need to have 2^N overloads because of all the const/non-const possible combinations).

Starting from C++11, C++ lets programmers perform perfect forwarding, which means that they can forward the parameters passed to a function template to another function call inside it without losing their own qualifiers (const-ref, ref, value, rvalue, etc.).

To use this technique, the invoke function template in the example must have arguments passed as rvalue references, and the std::forward function template, which is in charge of performing the type deduction and forwarding the arguments to the invoked function with its own reference, const-reference, or rvalue-reference qualifiers, must be used. Using this technique, the code becomes something like this:

#include <iostream>
#include <string>
#include <utility>
 
void sum(int a, int b)
{
    std::cout << a + b << std::endl;
}
 
void concat(const std::string& a, const std::string& b)
{
    std::cout << a + b << std::endl;
}
 
void successor(int a, int& b)
{
    b = ++a;
}
 
template <typename PROC, typename A, typename B>
void invoke(PROC p, A&& a, B&& b)
{
    p(std::forward<A>(a), std::forward<B>(b));
}
 
int main()
{
    invoke(sum, 10, 20);
    invoke(concat, "Hello", "world");
    int s = 0;
    invoke(successor, 10, s);
    std::cout << s << std::endl;
    return 0;
}

What is this technique used for?

For example, consider this class:

struct A { };
struct B { int a; int b; };
struct C { int a; int b; string c; };
struct D
{
public:
    D(int a) {}
};

Programmers want to have a factory function template that will let them run this code:

int main()
{
    auto a = factory<A>();
    auto b = factory<B>(10, 20);
    auto c = factory<C>(30, 40, "Hello");
    auto d = factory<D>(10);
     
    std::cout << c->c << std::endl;
}

As can be seen, the factory function template must be a variadic-template-based function, so a solution would be this one:

template <typename T, typename ... ARGS>
std::unique_ptr<T> factory(const ARGS&... args)
{
    return std::unique_ptr<T>{new T { args... }};
}

Notice that the std::make_unique<T> helper template method works like this example and serves the same purpose: create a new std::unique_ptr of type T, forwarding the parameters passed to its constructor.

Nice, and it works as expected. But the problem of losing qualifiers arises again. What happens with the following code?


If programmers try to use this struct in this way:

int main()
{
    int x = 2;
    auto e = factory<E>(x);
    std::cout << x << std::endl;  
}

They will get an error because x is an int&, not a const int&.

Fortunately, perfect forwarding is the way to go:

#include <iostream>
#include <string>
#include <utility>
 
struct A { };
struct B { int a; int b; };
struct C { int a; int b; string c; };
struct D
{
public:
    D(int a) {}
};
 
struct E
{
    int& e;
    E(int& e) : e{e} { e++; }
};
 
template <typename T, typename ... ARGS>
std::unique_ptr<T> factory(ARGS&&... args)
{
    return std::unique_ptr<T>{new T { std::forward<ARGS>(args)... }};
}
 
int main()
{
    auto a = factory<A>();
    auto b = factory<B>(10, 20);
    auto c = factory<C>(30, 40, "Hello");
    auto d = factory<D>(10);
     
    int x = 2;
    auto e = factory<E>(x);
    std::cout << x << std::endl;
}

Perfect forwarding also helps avoid writing several overloads of functions to support move semantics and copy semantics.

For example:

#include <iostream>
 
struct X
{
    X() { std::cout << "ctor" << std::endl; }
    X(const X&) { std::cout << "copy ctor" << std::endl; }
    X(X&&) { std::cout << "move ctor" << std::endl; }
};
 
struct Wrapper
{
    X w;
     
    Wrapper(const X& w) : w{w} { }
};
 
int main()
{
    Wrapper w1{X {}};
    std::cout << "***" << std::endl;
    X y;
    Wrapper w2{y};
}

This produces the output:

ctor
copy ctor
***
ctor
copy ctor

The little problem here is that when w1 is being constructed, the instance of X is a temporary instance that will be destroyed immediately after invoking the Wrapper constructor. In this case, invoking the move constructor should be better (performance-wise).

So, the programmers can create a second constructor and modify the Wrapper class to be like this:

struct Wrapper
{
    X w;
     
    Wrapper(const X& w) : w{w} { }   
    Wrapper(X&& w): w{std::move(w)} { } // Adding a overloaded constructor
};

Cool! It works as expected:

ctor
move ctor
***
ctor
copy ctor

When constructing w1, the Wrapper constructor with an rvalue reference parameter is used. In the example with a constructor that takes one parameter, this works nicely and is easy to maintain, but with constructors or functions that take many parameters, the same maintainability issues mentioned above arise again. So, programmers can rely on perfect forwarding to let the compiler decide which constructor to use and generate the required (and desired) code:

struct Wrapper
{
    X w;
     
    template <typename Q>
    Wrapper(Q&& w) : w{std::forward<Q>(w)} { }
};

Nice, isn’t it?

std::forward<T> is declared in the header file <utility>

C++: reference_wrapper

This small program:

#include <iostream>
#include <functional>
  
void add(int a, int b, int& r)
{
    r = a + b;
}
 
int main()
{
    int result = 0;
     
    using namespace std::placeholders;
    auto f = std::bind(add, _1, 20, result);
     
    f(80);
     
    std::cout << result << std::endl;
    return 0;
}

Supposedly adds 80 to 20 and prints the result; it compiles perfectly but when it gets executed it; it prints out…. 0!

Why?

Because the std::bind method parameters are passed using value semantics and, thus, the “result” variable is copied before being passed to the bound function add. Why?

Because since std::bind does not know if the parameters will still be valid when the actual invocation is performed (programmers could pass a std::function object to another function passing local variables as arguments and invoking it from there).

The solution? Pretty simple:

int main()
{
    int result = 0;
     
    auto f = std::bind(add, _1, 20, std::ref(result));
     
    f(80);
     
    std::cout << result << std::endl;
    return 0;
}

The function std::ref was used, which sends the parameter as a reference to the bound function.

What does this function std::ref do?

It is a template function that returns a std::reference_wrapper object. A std::reference_wrapper is a class template that wraps a reference in a concrete object.

It can also be done in this way:

int main()
{
    int result = 0;
     
    std::reference_wrapper<int> result_ref(result);
    auto f = std::bind(add, _1, 20, result_ref);
     
    f(80);
     
    std:.cout << result << std::endl;
    return 0;
}

and everything would continue working as expected.

As it can be seen, programmers can pass a std::reference_wrapper by value, and everything will work properly because its copy constructor copies the reference (actually, the std::reference_wrapper implementations do not store a reference but a pointer to the data being referenced, but their methods expose it as an actual reference).

Other nice use of this would be in cases where programmers need to have a container of references (the actual objects are stored in other container or elsewhere, and programmers do not need or want to have copies or pointers to them). For example, having these classes:

class A { };
class B : public A { };

If programmers want to have local variables pointing to these objects and store such variables in a container:

int main()
{
  A a, c;
  B b, d;

  std::vector<A> v = { a, b, c, d };
}

Good? No! Bad at all! The programmers here are storing instances of class A in the vector. All instances of B will be copied as instances of A (losing their specific attributes, methods, and all the polymorphic behavior they could have, and so on).

One solution? Storing pointers:

int main()
{
  A a, c; 
  B b, d;
 
  std::vector<A*> v = { &a, &b, &c, &d };
}

It works, but it is not clear whether the container consumers will be responsible for freeing the objects.

Other solution? Using references:

int main()
{
  A a, c;
  B b, d;

  std::vector<A&> v = { a, b, c, d };
}

Looks nice, but it does not compile; because programmers cannot specify reference types in a vector.

Real solution: Using std::reference_wrapper:

int main()
{
  A a, c; 
  B b, d;
 
  std::vector<std::reference_wrapper<A>> v = { a, b, c, d };
}

Someone could argue: In what scenario is this thing useful?

If some developers are creating a UI frame using Java Swing, they probably create a subclass of the JFrame class, specify their visual components as member variables, and also add them to the JFrame‘s component list. Implementing something similar in C++ using std::reference_wrapper instances would be quite elegant.

C++: std::function and std::bind

std::function and std::bind were originally part of the Boost C++ Library, but they were incorporated into the C++11 standard.

std::function is a standard library template class that provides a very convenient wrapper for a simple function, a functor, a method, or a lambda expression.

For example, if programmers want to store several functions, methods, functors, or lambda expressions in a vector, they could write something like this:

#include <functional>
#include <iostream>
#include <string>
#include <vector>
 
void execute(const std::vector<std::function<void ()>>& fs)
{
    for (auto& f : fs)
        f();
}
 
void plain_old_func()
{
    std::cout << "I'm an old plain function" << std::endl;
}
 
class functor final
{
public:
    void operator()() const
    {
        std::cout << "I'm a functor" << std::endl;
    }
};
 
int main()
{
    std::vector<std::function<void ()>> x;
    x.push_back(plain_old_func);
     
    functor functor_instance;
    x.push_back(functor_instance);
    x.push_back([] ()
    {
        std::cout << "HI, I'm a lambda expression" << std::endl;
    });
     
    execute(x);
}

As it can be seen, in this declaration:

std::vector<std::function<void ()>> x;

a vector of functions is being declared. The void () part means that the functions stored there do not receive any arguments and do not return anything (i.e., they have void as the return type). If programmers wanted to define a function that receives two integers and returns an integer, they could declare std::function as:

int my_func(int a, int b) { return a + b; }
 
function<int (int, int)> f = my_func;

The standard library also includes a function called std::bind. std::bind is a template function that returns a std::function object which, as the name suggests, binds a set of arguments to a function.

In the first code example, the functions stored in the vector do not receive any arguments, but programmers might want to store a function that accepts arguments in the same vector. They can do this using std::bind.

Having this function:

void show_text(const std::string& t)
{
    std::cout << "TEXT: " << t << std::endl;
}

How can it be added to the vector of functions in the first code listing (if even possible, because they have different signatures)? It can be added like this in the main() function:

std::function<void ()> f = std::bind(show_text, "Bound function");
x.push_back(f);

The code above shows that std::bind takes a pointer to a function (it can also be a lambda expression or a functor) and a list of parameters to pass to that function. As a result, std::bind returns a new function object with a different signature because all the parameters for the function have already been specified.

For example, this code:

#include <functional>
#include <iostream>
  
int multiply(int a, int b)
{
    return a * b;
}
 
int main()
{
    using namespace std::placeholders;

    auto f = std::bind(multiply, 5, _1);
    for (int i = 0; i < 10; i++)
    {
        std::cout << "5 * " << i << " = " << f(i) << std::endl;
    }

    return 0;
}

demonstrates another usage of std::bind. The first parameter is a pointer to the multiply function. The second parameter is the value passed as the first argument to multiply. The third parameter is called a “placeholder.” A placeholder specifies which parameter in the bound function will be filled by a runtime argument. Inside the for loop, f is called with only one parameter, and the second argument is provided dynamically.

Thanks to placeholders, even the order of arguments can be modified. For example:

#include <functional>
#include <string>
#include <iostream>
  
void show(const std::string& a, const std::string& b, const std::string& c)
{
    std::cout << a << "; " << b << "; " << c << std::endl;
}
 
int main()
{
    using namespace std::placeholders;

    auto x = std::bind(show, _1, _2, _3);
    auto y = std::bind(show, _3, _1, _2);
    auto z = std::bind(show, "hello", _2, _1);
     
    x("one", "two", "three");
    y("one", "two", "three");
    z("one", "two");
     
    return 0;
}

The output is:

one; two; three
three; one; two
hello; two; one

std::bind can also be used to wrap a method of a given object (i.e., an already instantiated one) into a function. For example, if programmers want to wrap the say_something method from the following struct:

struct Messenger
{
    void say_something(const std::string& msg) const
    {
        std::cout << "Message: " << msg << std::endl;
    }
};

into a std::function declared as follows:

using my_function = std::function<void (const std::string&)>;

The call to std::bind would look like this:

Messenger my_messenger; /* an actual instance of the class */

my_function 
    a_simple_function = std::bind(
        &Messenger::say_something /* pointer to the method */,
        &my_messenger, /* pointer to the object */,
        std::placeholders::_1 /* placeholder for the first argument in the method, as usual */
);

a_simple_function("Hello"); // will invoke the method Messenger::say_something on the object my_messenger

C++: Smart pointers, part 1

This is the first of several posts I wrote related to smart pointers:

  1. Smart pointers
  2. unique_ptr
  3. More on unique_ptr
  4. shared_ptr
  5. weak_ptr

Memory management in C is error-prone because keeping track of every block of memory allocated and deallocated can be confusing and stressful.

Although C++ has the same manual memory management as C, it provides additional features that make memory management easier:

  • When an object is instantiated on the stack (e.g., Object o;), the C++ runtime ensures that the object’s destructor is invoked when the object goes out of scope (when the end of the enclosing block is reached, a premature ‘return’ is encountered, or an exception is thrown), thereby releasing all memory and resources allocated for that object. This very nice feature is called RAII.
  • (Ab)using the feature of operator overloading, we can create classes that simulate pointer behaviour. These classes are called: Smart pointers.
Continue reading “C++: Smart pointers, part 1”

C++: C++-style listener list

Sometimes, it is useful to create a class to handle listeners that will be notified when something occurs in a given context. This is a common pattern (the Observer pattern) used in Java Swing, where an event triggers the invocation of one or more functions waiting for that event to occur.

In the example below, written in Java, the class instances perform some task, and the programmers want to be notified when the task has been completed:

public class Task
{
  public void doSomething() { }
 
  public void addTaskListener(TaskListener t);
}
 
public interface TaskListener
{
  void taskFinished(TaskEvent e);
}
 
public static void main(String... args)
{
  Task t = new Task();
  final String name = "TASK 123";

  t.addTaskListener(new TaskListener()
  {
    public void taskFinished(TaskEvent e)
    {
      System.out.println("Task finished: " + name);
    }
  });

  t.addTaskListener(new TaskListener()
  {
    public void taskFinished(TaskEvent e)
    {
      System.out.println("This is a second listener");
    }
  });
  t.doSomething();
}

How can this be implemented as idiomatically as possible in C++?

The first and most basic approach would be to use function pointers (in fact, an anonymous class in Java, as in the example, has access to the attributes of the class where it was defined as well as to all local variables marked as final; however, this cannot be done in the same way from an external function).

So, what would the C++ way of doing this look like?

The caller can be implemented as follows using C++ lambdas:

int main()
{
  Task t;
  std::string name = "TASK 123";
  t.addTaskListener([&name]
  {
    std::cout << "Task finished: " << name << std::endl;
  });

  t.addTaskListener([]
  {
    std::cout << "This is a second listener" << std::endl;
  });
  t.doSomething();
}

This is concise, elegant, and powerful: the name local variable can be captured by the lambda function as a closure.

The Task implementation should have a vector of listeners and should be able to access them when the task is successfully executed:

class Task
{
  private:
   std:: vector<TaskListener> listeners;
 
  public:
    void addTaskListener(TaskListener lis)
    {
      listeners.push_back(lis);
    }
 
    void doSomething()
    { 
      ...
      invokeListeners();
    }
 
  private:
    void invokeListeners()
    {
      for (TaskListener lis : listeners)
        lis();
    }
};

The problem is: How should TaskListener be declared?

Could it be a template parameter of a class template?

Answer: No.

Why?

Because each lambda function (as shown in the second example) is, under the hood, a class with a functor; so, there is no way to declare it as one single class and use it for two different classes (two lambda functions with different closures are implemented by the compiler as two unrelated classes).

As a second idea, the addTaskListener method could be implemented this way:

template <typename TaskListener>
void addTaskListener<Tasklistener t>
{
  listeners.add(t);
}

However, in that case, another new problem arises: how could the listeners vector be declared in a way that allows programmers to store one element of a given type and another of a different type?

The correct solution is to use the std::function abstraction.

std::function is a template class that can wrap a function, a functor, or a method, making it very suitable for this problem.

Thus, in the example, TaskListener could be only an alias to a std::function:

#include <functional>
 
using TaskListener = std::function<void ()>;

The parameterized type void () specifies that the function does not receive any arguments and returns void.

More on std::function here.

C++: Variadic templates (functions)

A very interesting feature introduced in C++11 is called “variadic templates,” which, in short, are template classes and functions that can accept a variable number of parameterized types. They can be useful for several things, for example:

  • Providing type-safe replacements for functions with a variable number of arguments (stdarg.h).
  • Allowing the user to create instances of n-tuples.
  • Creating type-safe containers with elements of various types.

This post takes a look at variadic template functions.

For example, consider a function called show() that accepts any number of parameters and displays them separated by whitespace.

Thus, the following calls would be valid:

show(1, 2, 3); // that would output 1 2 3
show("Today is", dayOfTheWeek); // that would output "Today is Tuesday"
show(p1, p2, p3, p4, p5);

In plain old C, a function with a similar, though not identical, signature could be implemented using the variable argument functions mechanism provided by C, along with the functions, types, and macros defined in the stdarg.h library. However, there are two problems with that approach:

  1. The number of arguments must be provided explicitly or implicitly. A good example of this is the C printf function. When declaring its signature, the number of format specifiers used implicitly defines the number of parameters that need to be accessed. For example, printf("%d %s", a, b); knows that there are two variables, and printf("%d %d %d", x, y, z); knows that there are three.
  2. The function is not type-safe in the sense that the programmer is responsible for determining the type of each variadic argument (that’s what the “%s” or “%d” in printf are used for).
void show(int n, ...)
{
    va_list x;
    va_start(x, n);
    for (int i = 0; i < n; i++)
    {
      // retrieve the parameter with va_arg and show it. There is no type info here.
    }

    va_end(x);
}

With the example above, since the type of each parameter after n is not specified, the supported types should be documented somehow; otherwise, the behavior will not be deterministic.

Before C++11, there were two partial solutions to this problem: one would be to create several overloaded functions, similar to this implementation:

template <typename T1>
void show(const T1& t1)
{
  std::cout << t1 << std::endl;
}

template <typename T1, typename T2>
void show(const T1& t1, const T2& t2)
{
  std::cout << t1 << " " << t2 << std::endl;
}

template <typename T1, typename T2, typename T3>
void show(const T1& t1, const T2& t2, const T3& t3)
{
  std::cout << t1 << " " << t2 << " "  << t3 << std::endl;
}

… and so on.

The other solution would be to have a base class (similar to the Java object model) and implement a method similar to this one:

void show(const Object* o1, const Object* o2 = nullptr, const Object* o3 = nullptr, const Object* o4 = nullptr, const Object* o5 = nullptr, const Object* o6 = nullptr)
{
  std::cout << o1->toString() << " ";
  if (o2)
      std::cout << o2->toString() << " ";
  if (o3)
    std::cout << o3->toString() << " ";
  if (o4)
    std::cout << o4->toString() << " ";
  if (o5)
    std::cout << o5->toString() << " ";
  if (o6)
    std::cout << o6->toString() << " ";

  std::cout << std::endl;
}

Though they would work, both approaches have their weaknesses. Both will support only a fixed number of arguments. In the first implementation, the programmer must provide N overloads to support N parameters, and in the second implementation, the programmer must provide a class hierarchy to make it work.

Variadic templates perform a type expansion similar to the template-based implementation (my first solution above), but this is done by the compiler instead of the programmer.

What is interesting about such expansion is that it is performed recursively.

This code implements the show function using variadic templates:

template <typename T>
void show(const T& value)
{
  std::cout << value << std::endl;
}

template <typename U, typename... T>
void show(const U& head, const T&... tail)
{
   std::cout << head << " ";
   show(tail...);
}

The first overload will be the base case, where either a single parameter is passed to the show() method or when all the other overloads have already been expanded.

The second overload is very interesting because we declare a function that takes two elements: U and T. U represents a concrete type (the type of the element to be actually printed), while T represents a list of types (notice the ... syntax). The argument list of the function is also interesting: head will be a const reference to a value of type U, and ...tail will represent a set of const references to several types.

Now, look at the implementation. We take the head and display it using std::cout, and then invoke another overload of show() by passing the tail list of parameters The tail... syntax is called parameter pack expansion, and it is similar to taking all the arguments that tail represents and “expanding” them as individual parameters in the function call. At this point, if the list of parameters contains more than one type, the compiler will create a new overload for this method. If the list of parameters contains only one type, the compiler will invoke the first overload already defined.

Amazing, isn’t it?

This feature is heavily used in variadic template-based classes in the Standard Library, such as std::C++11: std::tuple and C++17: std::variant.

C++: nullptr

In C and C++, the preprocessor definition NULL is/was used to explicitly indicate that a pointer is not pointing anywhere right now.

The problem with NULL is that underneath it is just a plain 0, something like this:

#define NULL 0

The following code excerpt shows how this can turn into a problem:

#include <iostream>
 
void m(int x)
{
    std::cout << x << endl;
}
 
void m(const char* x)
{
    std::cout << (x == NULL ? "NULL" : x) << std::endl;
}
 
int main()
{
  m(12);
  m(NULL);
  return 0;
}

When that code is compiled, the following error is displayed:

test.cpp: In function 'int main()':
test.cpp:19:9: error: call of overloaded 'm(NULL)' is ambiguous
test.cpp:19:9: note: candidates are:
test.cpp:5:6: note: void m(int)
test.cpp:10:6: note: void m(const char*)

Why does the compiler consider the m(NULL) ambiguous?

Because it cannot decide if NULL is actually a pointer (because it is a 0) or an integer (because NULL is… a 0).

C++11 introduces the literal nullptr of type std::nullptr_t; a literal that unambiguously represents a pointer pointing nowhere, eliminating the concept of being a pointer pointing to memory address 0.

It has these advantages:

  • It is a strongly typed null pointer, like Java or C# null.
  • No ambiguity when trying to pass a null pointer to something accepting, say, an int.
  • It is a literal and a keyword, so it cannot be defined or used as a symbolic name.
  • It cannot be casted automatically to a numeric type, as NULL can.

So, if the example above is replaced with this construction, there is this code:

int main()
{
  m(12);
  m(nullptr);
  return 0;
}

The code will compile and execute with no problems.

Since the type of nullptr is std::nullptr_t, which is a native type, programmers can also write a specific overload when the nullptr literal is passed as a parameter, as in the following example:

void m(int x)
{
    std::cout << x << std::endl;
}
 
void m(const char* x)
{
    std::cout << x << std::endl;
}
 
void m(nullptr_t)
{
    std::cout << "nullptr!" << std::endl;
}
 
int main()
{
  m(12);
  m(nullptr);
  return 0;
}

C++: Range-based for loop

Before C++11, when programmers wanted to display the elements stored in a vector, they had to write something like this:

template <typename T>
void show(const T& x)
{
    for (typename T::const_iterator i = x.begin(); i != x.end(); ++i)
        std::cout << *i << std::endl;
}

That method will be useful to show any collection that has a begin() and an end() and an iterator with an operator++(int), an operator!=() and an operator*() properly implemented.

C++11 and later versions ship with a very useful range-based for loop that makes iterations easier to write and read. This new for loop works also with plain-old arrays.

So, the code above can be rewritten like this in modern C++:

template <typename T>
void show(const T& x)
{
    for (auto& i : x)
        std::cout << i << std::endl;
}

As shown, the syntax is very similar to Java’s “enhanced-for” loop, and the resulting code is much easier to write and understand compared to the old version.

In the next example, you can see how this for loop can be used with several containers and arrays:

#include <vector>
#include <array>
#include <iostream>
  
template <typename T>
void show(const T& t)
{
    for (auto& i : t)
        std::cout << i << std::endl;
}
 
int main()
{
    int ints[] = { 10, 20, 30, 40, 50 };
    show(ints);
 
    std::cout << "*****" << std::endl;
 
    std::vector<std::string> s = { 
            "Monday", "Tuesday",
            "Wednesday", "Thursday",
            "Friday", "Saturday", "Sunday"
    };
 
    show(s);
     
    std::cout << "*****" << std::endl;
     
    std::array<string, 12> m = {
            "January", "February",
            "March", "April", "May",
            "June", "July", "August",
            "September", "October",
            "November", "December"
    };
 
    show(m);                            
    std::cout << "*****" << std::endl;
 
    return 0;   
}

Custom classes can also be iterated using the new for loop if the required methods are implemented, as in this example:

#include <vector>
#include <array>
#include <iostream>
 
template <typename T>
void show(const T& t)
{
    for (auto& i : t)
        std::cout << i << std::endl;
}
 
 
class RangeIterator
{
    private:
        int _index;
         
    public:
        explicit RangeIterator(int index) : _index(index) { }
         
        bool operator!=(const RangeIterator& x) const
        {
            return _index != x._index;
        }
         
        const int& operator*() const
        {
            return _index;
        }
         
        int& operator++()
        {
            return ++_index;
        }
};
 
template <int N, int M>
class Range
{
    public:
        using const_iterator = const RangeIterator;
         
        const_iterator begin() const
        {
            return const_iterator{N};
        }
         
        const_iterator end() const
        {
            return const_iterator{M};
        }
};
 
int main()
{
    Range<10, 20> r;
    show(r);
 
    return 0;   
}

Programmers can even iterate over a range of numbers (like the classic for loop) in this very elegant way:

int main()
{
    for (auto i : Range<10, 20>{})
    {
        std::cout << i << std::endl;
    }
}

The class to be iterated needs to have begin() and end() methods that return an iterator.

An iterator is basically a class that implements operator++(), operator!=(), and operator*() to access the next element, verify if there are more elements, and return the current element, respectively. Its semantics mimic pointer arithmetic to behave similarly to how a plain old array can be iterated.

C++: Move semantics

This example involves a class A and a container called List<T>. As shown, the container is essentially a wrapper around std::vector.

There is also a function called getNObjects that returns a list containing N instances of class A.

#include <vector>
#include <string>
#include <iostream>
 
class A
{
public:
    A() = default;
    ~A() = default;
    A(const A& a) { std::cout << "copy ctor" << std::endl ; }
     
    A& operator=(const A&)
    {
        std::cout << "operator=" << std::endl;
        return *this;
    }
};
 
template <typename T>
class List
{
private:
    std::vector<T>* _vec;
     
public:
    List() : _vec(new vector<T>()) { }
    ~List() { delete _vec; }
     
    List(const List<T>& list)
        : _vec(new vector<T>(*(list._vec)))
    {
    }
     
    List<T>& operator=(const List<T>& list)
    {
        delete _vec;
        _vec = new vector<T>(*(list._vec));
        return *this;
    }
     
    void add(const T& a)
    {
        _vec->push_back(a);
    }
     
    int getCount() const
    {
        return static_cast<int>(_vec->size());
    }
     
    const T& operator[](int i) const
    {
        return (*_vec)[i];
    }
};
  
List<A> getNObjects(int n)
{
    List<A> list;
    A a;
    for (int i = 0; i< n; i++)
        list.add(a);
 
    std::cout << "Before returning: ********" << std::endl;
    return list;
}
 
int main()
{
    List<A> list1;
    list1 = getNObjects(10);    
    return 0;
}

When this code runs, it will produce an output like this:

...
...
copy ctor
copy ctor
Before returning: ********
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor

The number of calls to the copy constructor equals the number of objects in the list!

Why?

Because when the getNObjects() function returns a list, all its attributes are copied (i.e., the internal vector is copied) to the list that receives the result (list1), and then the local list inside the function is destroyed (triggering the destructor for each object in the list). Though this is logically correct, it results in poor performance due to many unnecessary copies and destructions.

Starting from C++11, a new type of reference is available to address this problem: rvalue references. An rvalue reference binds to a temporary object (rvalue), which is typically the result of an expression that is not bound to a variable. Rvalue references are denoted using the symbol &&.

With rvalue references, programmers can create move constructors and move assignment operators, which improve performance when returning or copying objects in cases like this example.

How does this work?

In the example, the List<T> class contains a pointer to a vector. What happens if, instead of copying every object in the std::vector, the programmers “move” the vector pointer from the local list inside the function to the list that receives the result? This would save a lot of processing time by avoiding unnecessary copies and destructions.

Thus, the move constructor and move assignment operator work as follows: They receive an rvalue reference to the list being moved, “steal” its data, and take ownership of it. Taking ownership means that the object receiving the data is responsible for releasing all resources originally managed by the moved-from object (achieved by setting the original object’s pointer to nullptr).

Here’s how imove constructor and move assignment operator can be implemented for the List<T> class:

List(List<T>&& list) //move constructor
    : _vec(list._vec)
{
    list._vec = nullptr; //releasing ownership
}
     
List<T>& operator=(List<T>&& list)
{
    delete _vec;
    _vec = list._vec;
    list._vec = nullptr; //releasing ownership
    return *this;
}

With these changes, the output would be:

...
...
copy ctor
copy ctor
Before returning: ********

All the copy constructor calls after the “Before returning” line are avoided.

Isn’t that great?

What other uses do rvalue references have?

Here’s an example of a simple swap function for integers:

void my_swap(int& a, int& b)
{
  int c = a;
  a = b;
  b = c;
}

Straightforward enough. But what if, instead of swapping two integers, we needed to swap two large objects (such as vectors, linked lists, or other complex types)?

template <typename T>
void my_swap(T& a, T& b)
{
  T c = a;
  a = b;
  b = c;
}

If the copy constructor of class T is slow (like the std::vector copy constructor), this version of my_swap can have very poor performance.

Here’s an example demonstrating the issue:

#include <iostream>
#include <string>
  
class B
{
    private: int _x;
    public:
        B(int x) : _x(x) { cout << "ctor" << endl; }
         
        B(const B& b) : _x(b._x)
        {
            std::cout << "copy ctor" << std::endl;
        }
         
        B& operator=(const B& b)
        {
            _x = b._x;
            std::cout << "operator=" << std::endl;
            return *this;
        }
 
        friend std::ostream& operator<<(std::ostream& os, const B& b)
        {
            os << b._x;
            return os;
        }
         
};
 
template <typename T>
void my_swap(T& a, T& b)
{
    T c = a; //copy ctor, possibly slow
    a = b;   //operator=, possibly slow
    b = c;   //operator=, possibly slow
}
 
int main()
{
    B a(1);
    B b(2);
    my_swap(a, b);
    std::cout << a << "; " << b << std::endl;
    return 0;
}

The output is:

ctor
ctor
copy ctor
operator=
operator=
2; 1

The class B is simple, but if the copy constructor and assignment operator are slow, my_swap‘s performance will suffer.

To add move semantics to class B, move constructor and move assignment operator must be implemented:

B(B&& b)  : _x(b._x)
{
    std::cout << "move ctor" << std::endl;
}
         
B& operator=(B&& b)
{
    _x = b._x;
    std::cout << "move operator=" << std::endl;
    return *this;
}

However, the move constructor and assignment operator will not be invoked automatically. In my_swap, the compiler does not know if it should use the copy or move versions of the constructors and assignment operators.

This problem can be fixed by explicitly telling the compiler to use move semantics using the function template std::move():

template <typename T>
void my_swap(T& a, T& b)
{
    T c = std::move(a); //move ctor, fast
    a = std::move(b);   //move operator=, fast
    b = std::move(c);   //move operator=, fast
}

The std::move function casts an lvalue to an rvalue reference, signaling to the compiler that it should use the move constructor and assignment operator.

The updated output is:

ctor
ctor
move ctor
move operator=
move operator=
2; 1

The entire standard library has been updated to support move semantics.

Perfect forwarding is another feature built on top of rvalue references.

C++: Lambda expressions

Having this Person class:

class Person
{
  private:
    std::string firstName;
    std::string lastName;
    int id;

  public:
    Person(const std::string& fn, const std::string& ln, int i)
    : firstName{fn}
    , lastName{ln}
    , id{i}
    {
    }

    const std::string& getFirstName() const { return firstName; }
    const std::string& getLastName() const { return lastName; }
    int getID() const { return id; }
};

The programmers need to store several instances of this class in a vector:

std::vector<Person> people;
people.push_back(Person{"Davor", "Loayza", 62341});
people.push_back(Person{"Eva", "Lopez", 12345});
people.push_back(Person{"Julio", "Sanchez", 54321});
people.push_back(Person{"Adan", "Ramones", 70000});

If they want to sort this vector by person ID, a PersonComparator must be implemented to be used in the std::sort algorithm from the standard library:

class PersonComparator
{
  public:
     bool operator()(const Person& p1, const Person& p2) const
     {
        return p1.getID() < p2.getID();
     }
};

PersonComparator pc;
std::sort(people.begin(), people.end(), pc);

Before C++11, the programmers needed to create a separate class (or alternatively a function) to use the sort algorithm (actually to use any standard library algorithm).

C++11 introduced “lambda expressions”, which are a nice way to implement that functionality to be passed to the algorithm exactly when it is going to be used. So, instead of defining the PersonComparator as shown above, the same functionality could be achieved by implementing it in this way:

std::sort(people.begin(), people.end(), [](const Person& p1, const Person& p2)
{
  return p1.getID() < p2.getID();
});

Quite simple and easier to read. The “[]” square brackets are used to mark the external variables that will be used in the lambda context. “[]” means: “I do not want my lambda function to capture anything”; “[=]” means: “everything passed by value” (thanks Jeff for your clarification on this!!); “[&]” means: “everything passed by reference”.

Given the vector declared above, what if the programmers want to show all instances inside it? They could do this before C++11:

std::ostream& operator<<(std::ostream& os, const Person& p)
{
    os << "(" << p.getID() << ") " << p.getLastName() << "; " << p.getFirstName();
    return os;
}

class show_all
{
public:
    void operator()(const Person& p) const
    { 
        std::cout << p << std::endl;
    }
};

show_all sa;
std::for_each(people.begin(), people.end(), sa);

And with lambdas the example could be implemented in this way:

std::for_each(people.begin(), people.end(), [](const Person& p)
{
    std::cout << p << std::endl;
});