Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this virtual constexpr function not recognised as constant?

I have the following example code using virtual constexpr from C++20 which does not compile:

enum legCount {
    APODA = 0,
    BIPEDAL = 2,
    QUADRUPEDAL = 4,
};

class Animal {
public:
    constexpr virtual legCount getLegCount() = 0;
};

class Tiger : public Animal {
public:
    constexpr legCount getLegCount() { return QUADRUPEDAL; }

    void manipulateLegsArray() {
        unsigned char arr[getLegCount()];
    }
};

This code compiles with Clang however MSVC complains that getLegCount in unsigned char arr[getLegCount()]; does not evaluate to a constant expression (failure was caused by a read of a variable outside its lifetime). Is MSVC correct here and if so why is this?

Further, how can I mimic this functionality in a conformant way? I would like to have an abstract base class where all derived classes must implement the function and the function must be a constexpr.

Exact compiler error message as follow:

D:\Projects\temp\demo\main.cpp(17,32): error C2131: expression did not evaluate to a constant [D:\Projects\temp\out\demo\demo.vcxproj]
D:\Projects\temp\demo\main.cpp(17,21): message : failure was caused by a read of a variable outside its lifetime [D:\Projects\temp\out\demo\demo.vcxproj]
D:\Projects\temp\demo\main.cpp(17,21): message : see usage of 'this' [D:\Projects\temp\out\demo\demo.vcxproj]
like image 359
user_5309734 Avatar asked Sep 20 '25 04:09

user_5309734


1 Answers

manipulateLegsArray function can be called at runtime by another class that inherits from your class, so getLegCount() must be resolved at runtime, your array now becomes a variable length array, which MSVC doesn't support, it is only supported by clang/gcc.

you could enforce the derived class to implement something that is constexpr using CRTP.

enum legCount {
    APODA = 0,
    BIPEDAL = 2,
    QUADRUPEDAL = 4,
};

template< typename T>
class Animal {
public:
    static constexpr legCount getLegCount()
    {
        return T::legCount_v;
    }
};

class Tiger : public Animal<Tiger> {
public:
    constexpr static legCount legCount_v = QUADRUPEDAL;

    void manipulateLegsArray() {
        unsigned char arr[getLegCount()];
    }
};
like image 148
Ahmed AEK Avatar answered Sep 22 '25 16:09

Ahmed AEK