Compile-time sizes for range adaptors

In my previous blog post, we’ve discussed the static constexpr std::integral_constant idiom to specify the size of a range at compile-time. Unlike the standard, our (think-cell’s) ranges library at think-cell already supports compile-time sizes natively, so I was eager to try the idiom there and see how it works out in practice.

namespace tc
{
    template <typename Rng>
    constexpr auto size(Rng&& rng); // runtime-size of a range, like std::ranges::size

    template <typename Rng> requires tc::has_constexpr_size<Rng>
    constexpr auto constexpr_size = ; // compile-time size of a range given its type
}
» read more »
Jonathan

The new static constexpr std::integral_constant idiom

The size of std::array<T, N> is known at compile-time given the type. Yet it only provides a regular .size() member function:

template <typename T, std::size_t N>
struct array {
    constexpr std::size_t size() const {
        return N;
    }
};

This is annoying if you’re writing generic code that expects some sort of compile-time sized range.

» read more »
Jonathan

Should we stop writing functions?

… and use lambdas instead?

That is, instead of:

int sum(int a, int b) {
    return a + b;
}

You’d write:

constexpr auto sum = [](int a, int b) -> int {
    return a + b;
};

Hear me out.

» read more »
Jonathan

Constrain your user-defined conversions

Sometimes you want to add an implicit conversion to a type. This can be done by adding an implicit conversion operator. For example, std::string is implicitly convertible to std::string_view:

class string { // template omitted for simplicity
public:
    operator std::string_view() const noexcept
    {
       return std::string_view(c_str(), size());
    }
};

The conversion is safe, cheap, and std::string and std::string_view represent the same platonic value — we match Tony van Eerd’s criteria for implicit conversions and using implicit conversions is justified.

However, even when all criteria are fulfilled, the conversion can still be dangerous.

» read more »
Jonathan

Technique: Proof types to ensure preconditions

Consider a library using hidden global state that needs to be initialized by calling an initialization function. If you don’t call the function before you start using the library, it crashes.

How do you design the library in such a way that it is impossible to use it before initialization?

One idea is to use a technique where you create a special proof type, which needs to be passed as an additional parameter. Let’s look at it in more detail.

» read more »
Jonathan