Код:
#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
}
Ошибка в строке [2]
из-за строки [1]
:
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
MSV C не удалось скомпилировать, когда итератор является полем в классе, но успешно скомпилировал, когда итератор является локальной переменной. В сообщении об ошибке говорится, что выражение не является константой, поскольку вызов функции включает приведение типа Dynami c (см. Выше).
G CC и Clang успешно скомпилированы в обоих случаях.
Интересно, что в Visual Studio значение y
можно предварительно просмотреть (наведя на него курсор), как и любую другую переменную constexpr
(что заставляет меня думать, что MSV C, вероятно, неверно).
Редактировать: Последняя предварительная версия MSV C по-прежнему не компилируется.
Редактировать: Я сообщил об этой ошибке в Microsoft здесь .
Вопросы :
Какой компилятор является правильным в соответствии со стандартом?
Есть ли лучший способ сделать то, что я делаю (т.е. написание базы класс для наследования классов итераторов)?