Posts for: #Let's Try C++20

Let’s try C++20 | Erase elements in a container with std::erase()

Imagine you have a vector of integers and you want to remove all zeros. It sounds like a simple task, right? Well, before C++20, it wasn’t that obvious. Let’s see how C++20 makes things easier.

Before

Since the beginning of C++, there is a free function named std::remove(). Young padawans may naively use it like this:

#include <iostream>
#include <vector>

int main() {
    std::vector data{12, 0, 654, 0, 4587, 0, 42};
    for (const auto& e: data) {
        std::cout << e << '\t';
    }

    std::cout << '\n';
    std::remove(data.begin(), data.end(), 0);

    for (const auto& e: data) {
        std::cout << e << '\t';
    }
}

They would get this weird result:

Let’s try C++20 | std::cmp_* functions

Today, I have discovered a very simple (but yet very efficient and useful) feature from C++20: the std::cmp_* functions. They allow you to compare 2 integers, which can have different signedness, without getting bitten by implicit conversions.

Let’s have a look at this piece of code:

#include <iostream>

int main()
{
    int a = -6;
    unsigned int b = 3;
    
    if (a < b) {
        std::cout << "OK: a is lower than b\n";
    } else {
        std::cout << "Oopsi!\n";
    }
}

Yes, you’ve guessed right: it prints “Oopsi!”.

Let’s try C++20 | std::is_constant_evaluated()

std::is_constant_evaluated() is one of the many new small features of C++20. Specified in P0595R2, this function is available in the <type_traits> header. Here is its description from cppreference:

constexpr bool is_constant_evaluated() noexcept;

Detects whether the function call occurs within a constant-evaluated context. Returns true if the evaluation of the call occurs within the evaluation of an expression or conversion that is manifestly constant-evaluated; otherwise returns false.

This sounds pretty straightforward.

Benefits for constexpr functions

This may be very interesting for constexpr functions. You probably know that you have no guarantee that a constexpr function is really executed at compile-time. This depends on how the function is called:

Let’s try C++20 | using enum

Proposal P1099R5 by Gašper Ažman and Jonathan Müller adds the possibility to write using enum my_enum; so that the names inside the enumeration my_enum can be used directly, without being preceded by my_enum::.

Let’s consider an enumeration like this:

enum class EnumWithALongName {
    FirstValue,
    SecondValue,
    YetAnotherValue
};

Until C++17, you had to write their fully qualified names to use the enumerators. Sometimes, it would make code quite verbose:

void process(EnumWithALongName value) {
    switch(value) {
        case EnumWithALongName:::FirstValue:
            // stuff
        case EnumWithALongName::SecondValue:
            // more stuff
        case EnumWithALongName::YetAnotherValue:
            // OK, I got it, we are dealing with EnumWithALongName...
    }
}

Thanks to C++20, we can now write:

Let’s try C++20 | explicit(bool)

From the many changes of C++20, let’s focus today on explicit(bool). This feature is described in P0892R2. The explicit keyword avoids implicit conversions by unexpectedly calling a constructor. With C++20, it is now possible to have a boolean condition as a “parameter” to the keyword.

How it works

This simple code makes it easy to understand how explicit(bool) works:

constexpr bool ENABLE_EXPLICIT = false;

struct Foo {
    explicit(ENABLE_EXPLICIT)
    Foo(int) {}
};

Foo a = 1;

This code compiles fine, but change ENABLE_EXPLICIT to true and you will get an error with clang-10.0.0: