Let's try C++20 | virtual constexpr functions
Tags: cpp, programming, todayilearned
Published: 2020-10-31 11:01:16

Once, I wondered if we could have `virtual constexpr` functions. It is now possible with C++20 so let's try!

## A Piece of Personal Experience

Two years ago, I several classes with a common point: base classes had a pure virtual function to request derived classes to return a constant. Something like this:

```cpp
struct Memory {
    // Capacity in bytes
    virtual unsigned int capacity() const = 0;
};
```

It was the base class for drivers to communicate with a particular memory chip. Each subclass that would return the size of the actual memory that handle. For instance, for the [Microchip's 25LC160C EEPROM](https://www.microchip.com/wwwproducts/en/25LC160C):

```cpp
struct EEPROM_25LC160C : Memory {
    unsigned int capacity() const override {
        return 2048;
    }
};
```

I asked myself: can I make this function `constexpr` because the size never changes for each class? Answer: it was not possible back then.

## Now with `virtual constexpr`

But guess what? This is now [possible in C++20](https://en.cppreference.com/w/cpp/language/constexpr):

> A `constexpr` function must satisfy the following requirements:
>- it must not be virtual (until C++20)
>- (...)

Code can now be:

```cpp
struct Memory {
    virtual constexpr unsigned int capacity() const = 0;
};

struct EEPROM_25LC160C : Memory {
    constexpr unsigned int capacity() const override {
        return 2048;
    }
};
```

Not that it is possible for the base function to be `constexpr` while the derived function is not. And vice versa.

## Examples

Great! But wait... How is this useful for me? Well, actually, for the moment, I don't have a clue 😅

Code like this works:

```cpp
constexpr EEPROM_25LC160C eeprom;
static_assert(eeprom.capacity() > 1024);
```

Before `virtual constexpr`, I would have to provide a public `static constexpr` member like this:

```cpp
struct EEPROM_25LC160C : Memory {
    static constexpr auto SIZE = 2048;

    unsigned int capacity() const override {
        return SIZE;
    }
};

static_assert(EEPROM_25LC160C::SIZE > 0);
```

C++20's version is an improvement but I think it's minor.

Another possible code:

```cpp
static constexpr EEPROM_25LC160C eeprom;

constexpr const Memory& getMemory() {
    return eeprom;
}
 
int main() {
    constexpr const Memory& memory = getMemory();
    static_assert(memory.capacity() > 1024);
}
```

OK... But without the `const`s is doesn't compile and having `const` objects is necessarily what I want.

Here is an example that doesn't compile (obviously):

```cpp
template<unsigned int startAddress, unsigned int bytesCount>
class Serializer {
private:
    EEPROM_25LC160C eeprom;
    static_assert(startAddress + bytesCount < eeprom.capacity());
};
 
int main() {
    constexpr EEPROM_25LC160C eeprom;
    Serializer<1500, 700> serializer;
}
```

```
<source>:15:47: error: invalid use of non-static data member 'memory'

    static_assert(startAddress + bytesCount < memory.capacity());

                                              ^~~~~~
```

I can try something else:

```cpp
template<unsigned int startAddress, unsigned int bytesCount>
class Serializer {
public:
    constexpr Serializer() {        
        static_assert(startAddress + bytesCount < eeprom.capacity());
    }

private:
    EEPROM_25LC160C eeprom;
};
 
int main() {
    constexpr EEPROM_25LC160C eeprom;
    constexpr Serializer<1500, 700> serializer;
}
```

Still, the code doesn't compile:

```
<source>:15:23: error: static_assert expression is not an integral constant expression

        static_assert(startAddress + bytesCount < eeprom.capacity());
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

## Conclusion

I have read the paper that proposed to add this feature to the C++ standard: ["Allowing Virtual Function Calls in Constant Expressions" by Peter Dimov and Vassil Vassilev](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1064r0.html).

Clearly, it doesn't sounds like a feature everyone will use it their everyday code. I will keep it in mind and I hope one day I will find a use-case in my code 😁

PS : here is an excellent article from Microsoft about the spaceship operator = [Simplify Your Code With Rocket Science: C++20’s Spaceship Operator](https://devblogs.microsoft.com/cppblog/simplify-your-code-with-rocket-science-c20s-spaceship-operator/)