Articles & Books

Automatic two-phase init—Krzysztof Ostrowski

Deferred initialisation for classes that inherit constructors, or Automatic two-phase init.

Deferred initialisation for classes that inherit constructors

by Krzysztof Ostrowski

From the article:

Constructor inheritance through using-declaration is a powerful technique that can be easily used to introduce pre-defined behaviour to custom types. As an example, consider a generic visitor design pattern implementation that is parametrised by the names of visitable types, and an unique tag that identifies given visitor template instance. Such an instance can be "mixed-in" into a custom type D by simply deriving from it... and inheriting its constructors to make it behave as it would be a Visitor template instance itself:

struct D
  : Visitor<
        A         // the tag
      , X, Y, Z   // "list" of visitable types
      >
{
    using Visitor::Visitor;
};
What if there is a need to run an "additional" initialisation code as it would be run in the D constructor if one were there? Bjarne Stroustrup suggests member-initializers that do half of a work we would like to do here. While direct member initialisation sets required initial values for all the members (except bit field members), it does not offer a direct way to execute custom code that makes use of those members, the custom code that typically resides in the constructor's body.
This article presents a solution that enables injection of a custom code to be executed once all the non-static members are initialised.

Ranges, Coroutines, and React: Early Musings on the Future of Async in C++—Eric Niebler

Eric Niebler shares his thoughts about the interaction of ranges and co-routines in his recent blog post.

Ranges, Coroutines, and React: Early Musings on the Future of Async in C++

by Eric Niebler

From the article:

Another way to look at this is that synchronous ranges are an example of a pull-based interface: the user extracts elements from the range and processes them one at a time. Asynchronous ranges, on the other hand, represent more of a push-based model: things happen when data shows up, whenever that may be. This is akin to the reactive style of programming.

By using ranges and coroutines together, we unify push and pull based idioms into a consistent, functional style of programming. And that’s going to be important, I think.

Quick Q: What are template deduction guides in C++17?

Quick A: A solution for automatic template resolution on constructors.

Recently on SO:

What are template deduction guides in C++17?

Template deduction guides are patterns associated with a template class that tell the compiler how to translate a set of parameter (and their types) into template arguments.

The simplest example is that of std::vector and its constructor that takes an iterator pair.

template<typename Iterator>
void func(Iterator first, Iterator last)
{
  vector v(first, last);
}

The compiler needs to figure out what vector<T>'s T type will be. We know what the answer is; T should be typename std::iterator_traits<Iterator>::value_type. But how do we tell the compiler without having to type vector<typename std::iterator_traits<Iterator>::value_type>?

You use a deduction guide:

template<typename Iterator> vector(Iterator b, Iterator e) -> vector<typename std::iterator_traits<Iterator>::value_type>;

This tells the compiler that, when you call a vector constructor matching that pattern, it will deduce the vector specialization using the code on the right of ->.

You need guides when the deduction of the type from the arguments is not based on the type of one of those arguments. Initializing a vector from an initializer_list explicitly uses the vector's T, so it doesn't need a guide.

The left side doesn't necessarily specify a constructor. The way it works is that, if you use template constructor deduction on a type, it matches the arguments you pass against all deduction guides (actual constructors provide implicit guides). If there is a match, it uses that to determine which template arguments to provide to the type. But overload resolution to determine which constructor to call happens after that.

This also means that you can use guides with aggregates and aggregate initialization:

template<typename T>
struct Thingy
{
  T t;
};

Thingy(const char *) -> Thingy<std::string>;

Thingy thing{"A String"}; //thing.t is a `std::string`.

So deduction guides are only used to figure out the type being initialized. The actual process of initialization works exactly as it did before, once that determination has been made.

Detection Idiom - A Stopgap for Concepts—Simon Brand

Concepts are not yet here, but there are solutions.

Detection Idiom - A Stopgap for Concepts

by Simon Brand

From the article:

Concepts is a proposed C++ feature which allows succinct, expressive, and powerful constraining of templates. They have been threatening to get in to C++ for a long time now, with the first proposal being rejected for C++11. They were finally merged in to C++20 a few months ago, which means we need to hold on for another few years before they’re in the official standard rather than a Technical Specification. In the mean time, there have been various attempts to implement parts of concepts as a library so that we can have access to some of the power of Concepts without waiting for the new standard. The detection idiom – designed by Walter Brown and part of the Library Fundamentals 2 Technical Specification – is one such solution. This post will outline the utility of it, and show the techniques which underlie its implementation.

The main() Course—Adi Shavit

A fanciful little post about li’l old main().

The main() Course

by Adi Shavit

From the article:

The function main() is a normal program’s entry point.

The shortest conforming C++ executable program is: int main(){}

Quick Q: Array Initialisation Compile Time - Constexpr Sequence

Quick A: Use integer_sequence with a helper function.

Recently on SO:

Array Initialisation Compile Time - Constexpr Sequence

1) How to implement that kind of integer_sequence?

template <std::size_t... Is>
constexpr auto make_sequence_impl(std::index_sequence<Is...>)
{
    return std::index_sequence<generate_ith_number(Is)...>{};
}

template <std::size_t N>
constexpr auto make_sequence()
{
    return make_sequence_impl(std::make_index_sequence<N>{});
}

2) Is it possible to build an std::array from that integer_sequence at compile time?

template <std::size_t... Is>
constexpr auto make_array_from_sequence_impl(std::index_sequence<Is...>)
{
    return std::array<std::size_t, sizeof...(Is)>{Is...};
}

template <typename Seq>
constexpr auto make_array_from_sequence(Seq)
{
    return make_array_from_sequence_impl(Seq{});
}

Usage:

int main()
{
    constexpr auto arr = make_array_from_sequence(make_sequence<6>());
    static_assert(arr[0] == 0);
    static_assert(arr[1] == 1);
    static_assert(arr[2] == 2);
    static_assert(arr[3] == 4);
    static_assert(arr[4] == 5);
    static_assert(arr[5] == 7);
}

Quick Q: vector of vector does not convert brace encloser list

Quick A: The constructor needs an extra {} pair.

Recently on SO:

vector does not convert brace encloser list

You have two options:

  1. add a constructor taking std::initializer_list<std::initializer_list<T>>
  2. eclose the init expression with another set of {} i.e.
Matrix<double> a{{

    { 17,    24,    1},

    { 23,    5,     7 },

    {  4,     6,    13 }

}};

Ok, I'll try a little explanation of what is going on here:

If there is no constructor taking a std::initializer_list then the outermost {} are always opening and closing the constructor call if you will, and not part of what you actually pass to the constructor.

Matrix<double> a{ {1, 2}, {3, 4} };
                ^ ^~~~~~~~~~~~~~ ^
                |  2 parameters  |
                |                |
                |                |
            opening            closing

As you can see this is taken as a constructor with 2 parameters, in this case 2 initializer_lists.

This is why you need another set of {}:

Matrix<double> a{ {{1, 2}, {3, 4}} };
                ^ ^~~~~~~~~~~~~~~~ ^
                |  1 parameter     |
                |                  |
                |                  |
            opening            closing

In order for the outermost {} to be considered an initializer_list then the constructor needs to have an overload taking a initializer_list. That is what is happening in the std::vector case.