DEV Community

Pierre Gradot
Pierre Gradot

Posted on • Edited on

Let's try C++20 | virtual constexpr functions

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:

struct Memory {
    // Capacity in bytes
    virtual unsigned int capacity() const = 0;
};
Enter fullscreen mode Exit fullscreen mode

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:

struct EEPROM_25LC160C : Memory {
    unsigned int capacity() const override {
        return 2048;
    }
};
Enter fullscreen mode Exit fullscreen mode

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:

A constexpr function must satisfy the following requirements:

  • it must not be virtual (until C++20)
  • (...)

Code can now be:

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

struct EEPROM_25LC160C : Memory {
    constexpr unsigned int capacity() const override {
        return 2048;
    }
};
Enter fullscreen mode Exit fullscreen mode

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:

constexpr EEPROM_25LC160C eeprom;
static_assert(eeprom.capacity() > 1024);
Enter fullscreen mode Exit fullscreen mode

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

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

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

static_assert(EEPROM_25LC160C::SIZE > 0);
Enter fullscreen mode Exit fullscreen mode

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

Another possible code:

static constexpr EEPROM_25LC160C eeprom;

constexpr const Memory& getMemory() {
    return eeprom;
}

int main() {
    constexpr const Memory& memory = getMemory();
    static_assert(memory.capacity() > 1024);
}
Enter fullscreen mode Exit fullscreen mode

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

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

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;
}
Enter fullscreen mode Exit fullscreen mode
<source>:15:47: error: invalid use of non-static data member 'memory'

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

                                              ^~~~~~
Enter fullscreen mode Exit fullscreen mode

I can try something else:

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;
}
Enter fullscreen mode Exit fullscreen mode

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());
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter fullscreen mode Exit fullscreen mode

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.

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

Top comments (1)

Collapse
 
gberthiaume profile image
G. Berthiaume

Great article, as always.
I just want constexpr in C2X. It seems such a nice language feature.