【发布时间】:2020-03-01 19:04:36
【问题描述】:
代码:
#include <cstddef>
template <typename value_type, typename iterator_type>
class array_iterator_base
{
protected:
value_type *ptr;
public:
constexpr array_iterator_base() : ptr(nullptr) {}
constexpr iterator_type &operator++()
{
++ptr;
return *static_cast<iterator_type *>(this); // [1]
}
};
template <typename value_type>
class array_iterator : public array_iterator_base<value_type, array_iterator<value_type>>
{
public:
constexpr array_iterator(value_type *ptr)
{
this->ptr = ptr;
}
};
template <typename value_type, std::size_t Size>
class array
{
public:
using iterator = array_iterator<value_type>;
value_type m_data[Size];
constexpr iterator begin() { return iterator(m_data); }
};
class Demo
{
using storage = array<int, 3>;
using iterator = typename storage::iterator;
private:
storage m_arr = { 1, 2, 3 };
iterator m_iter = m_arr.begin();
public:
constexpr Demo() {}
constexpr void field()
{
++m_iter; // MSVC: failed
}
constexpr void local_variable()
{
storage arr = { 1,2,3 };
iterator iter = arr.begin();
++iter; // MSVC: OK
}
};
constexpr int ok()
{
Demo demo;
demo.local_variable();
return 1;
}
constexpr int error()
{
Demo demo;
demo.field();
return 1;
}
int main()
{
constexpr int x = ok();
// GCC: OK
// Clang: OK
// MSVC: OK
constexpr int y = error(); // [2]
// GCC: OK
// Clang: OK
// MSVC: error
}
由于[1] 行导致[2] 行出错:
Expression did not evaluate to a constant.
Failure was caused by cast of object of dynamic type
array_iterator<value_type>
to type
iterator_type
with
[value_type=int]
[iterator_type=array_iterator<int>]
我自己正在编写一个数组类。我决定编写一个数组迭代器基类,以便任何数组迭代器类都可以从它继承以节省一些击键。为此,当需要返回迭代器本身时,我必须将基类强制转换为派生迭代器类,因此iterator_type &operator++() 重载中有return *static_cast<iterator_type *>(this);。
但是,在constexpr 上下文中,当迭代器是类中的字段时,MSVC 编译失败,但当迭代器是局部变量时编译成功。错误消息说表达式不是常量,因为函数调用涉及转换动态类型(见上文)。
GCC 和 Clang 在这两种情况下都编译成功。
有趣的是,在 Visual Studio 中,y 的值实际上可以预览(通过将光标悬停在其上),就像任何其他 constexpr 变量一样(这让我认为 MSVC 可能是错误的)。
编辑:MSVC 的最新预览版仍然无法编译。
编辑:我已将此错误报告给 Microsoft here。
问题:
根据标准,哪个编译器是正确的?
有没有更好的方法来做我正在做的事情(即为迭代器类编写一个基类来继承)?
【问题讨论】:
-
很高兴知道最新的 VS Preview 是否接受代码。
-
@Acorn 刚刚尝试使用 MSVC“Preview”(C++20 标准),它给出了相同的错误(默认为 C++17 标准);使用 C++14 标准也会出现同样的错误。
-
@durianice 我尝试改进格式以消除错误等。如果您不喜欢它,请随时恢复。
-
我不知道 MSVC 是否正确,但你不能让
operator++返回一个array_iterator_base&吗?这适用于 MSVC。 Demo -
看起来像一个 MSVC 错误。您应该提交错误(菜单帮助/发送反馈/报告问题...)。
标签: c++ visual-c++ visual-studio-2019 constexpr