为什么MSVC说对虚拟constexpr函数调用运算符的调用不会产生常量表达式



我有一个封装数组的类。它继承自为函数调用运算符定义一个virtual constexpr方法的抽象基类。在子类中,我覆盖所述方法并访问内部数组:

#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);
}

这是螺栓连接。

据我所知,这都是C++20中的合法代码,它允许virtual constexpr。G++10.3和Clang 12都接受这是有效的代码,但MSVC 19.33不接受它,声称变量F不是常数表达式:

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

什么东西?对我来说,这看起来像是MSVC中的一个编译器错误。我会进一步调查,但godbolt.org上的MSVC现在似乎已经关闭了。

我应该补充一点,只有当函数调用运算符方法是virtual时,问题才会出现——如果不是,问题就不会发生。

有人能提出建议吗?

User@Barry同意我的观点,认为这肯定是MSVC中的一个bug。

我已经提交了这个错误报告。

希望这个问题能尽快得到解决。

感谢大家的评论和进一步的见解,这非常有帮助!

我真的不知道为什么把_items放在基类中会让MSVC接受代码,也许在基类中没有_items的情况下虚拟重载的operator()让MSVC不知何故认为它不符合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];
}
};

导螺杆试验。

在此测试期间发现了另一个IntelliSense错误:如果_items没有在基类构造函数(_items{}(中初始化,IntelliSense将报告此错误,但代码可以很好地编译:

错误E0028:表达式必须具有常数值

最新更新