Home > Net >  Why does MSVC say a call to a virtual constexpr functional call operator does not result in a consta
Why does MSVC say a call to a virtual constexpr functional call operator does not result in a consta

Time:10-28

I have a class that wraps an array. It inherits from an abstract base class defining one virtual constexpr method for the function-call operator. In the child class, I override said method and access the internal array:

#include <cstddef>
#include <array>
#include <initializer_list>

template <typename T, std::size_t N>
class ContainerBase {
public:
    virtual constexpr const T& operator()(std::size_t i) const = 0;
};

template <typename T, std::size_t N>
class Container : public ContainerBase<T, N> {
public:
    constexpr Container(std::initializer_list<T> data) {
        std::copy(data.begin(), data.end(), _items.begin());
    }
    constexpr const T& operator()(std::size_t i) const override {
        return _items[i];
    }
private:
    std::array<T, N> _items;
};

int main () {
    constexpr Container<int, 3> C = {2, -91, 7};
    constexpr int F = C(1);

    static_assert(F == -91);
}

Here is the godbolt link.

To the best of my understanding, this is all legal code in C 20, which allows virtual constexpr. G 10.3 and Clang 12 both accept this as valid code, however MSVC 19.33 does not accept it, claiming that variable F is not a constant expression:

msvc_buggy_constexpr.cpp(29,21): error C2131: expression did not evaluate to a constant
msvc_buggy_constexpr.cpp(21,16): message : a non-constant (sub-)expression was encountered
msvc_buggy_constexpr.cpp(31,5): error C2131: expression did not evaluate to a constant
msvc_buggy_constexpr.cpp(21,16): message : a non-constant (sub-)expression was encountered

What gives? This looks like a compiler bug in MSVC to me. I would investigate further but MSVC on godbolt.org seems to be down right now.

I should add, the issue only presents itself when the function call operator method is virtual —when it is not, the issue does not occur.

Can anyone advise?

CodePudding user response:

User @Barry agrees with me that it's definitely a bug in MSVC.

I've submitted this bug report.

Hopefully the issue gets resolved soon.

Thanks all for your comments and further insights, it's very helpful!

CodePudding user response:

I'm not really sure why putting _items in the base class will make MSVC accepts the code, maybe the virtual overloaded operator() without _items being in the base class make MSVC somehow thinks that it's not qualified for constexpr.

template <typename T, std::size_t N>
class ContainerBase
{
protected:
    std::array<T, N> _items;
public:
    constexpr ContainerBase() : _items{} {};
    virtual constexpr const T& operator()(std::size_t i) const = 0;
};

template <typename T, std::size_t N>
class Container : ContainerBase<T, N>
{
public:
    constexpr Container(std::initializer_list<T> data) : ContainerBase<T, N>()
    {
        std::copy(data.begin(), data.end(), this->_items.begin());
    }
    constexpr const T& operator()(std::size_t i) const override
    {
        return this->_items[i];
    }
};

Test on godbolt.

Another IntelliSense bug was spotted during this test: if _items were not initialized in the base class constructor (_items{}), IntelliSense will report this error, but the code can be compiled just fine:

Error E0028: expression must have a constant value

  • Related