У меня есть векторная реализация, и я пытаюсь поместить сохраненные значения T
в оболочку.
Оболочка имеет ту же структуру памяти, что и T
, поэтому арифметика индексации / указателя массива c на T*
, кажется, работает правильно во время выполнения. Однако при попытке сделать то же самое в контексте constexpr
[g cc, clang, msvc] все отклоняют код. Также обратите внимание, что data()[0]
работает во всех случаях, но data()[1]
, data()[2]
et c не удается.
Должно ли это иметь место? Почему компилятор решает, что хорошо делать арифметику указателей c для SimpleVector
, но не для SimplerVector2
? Кроме того, безопасно ли использовать арифметику указателя времени выполнения c (которая работает)?
#include <array>
#include <cassert>
struct Wrapper
{
double b;
};
struct SimpleVector
{
std::array<double, 100> values;
constexpr const double* data() const { return &values[0]; }
};
struct SimpleVector2
{
std::array<Wrapper, 100> values;
constexpr const double* data() const { return &values[0].b; }
};
int main()
{
{
constexpr SimpleVector my_vec{1, 2, 3, 4, 5, 6};
assert(my_vec.data()[0] == 1); // OK
assert(my_vec.data()[1] == 2); // OK
assert(my_vec.data()[2] == 3); // OK
static_assert(my_vec.data()[0] == 1); // OK
static_assert(my_vec.data()[1] == 2); // OK
static_assert(my_vec.data()[2] == 3); // OK
}
{
constexpr SimpleVector2 my_vec{1, 2, 3, 4, 5, 6};
assert(my_vec.data()[0] == 1); // OK
assert(my_vec.data()[1] == 2); // OK
assert(my_vec.data()[2] == 3); // OK
// OK!!
static_assert(my_vec.data()[0] == 1);
// FAILS! read of dereferenced one-past-the-end pointer
// is not allowed in a constant expression
static_assert(my_vec.data()[1] == 2);
// FAILS! cannot refer to element 2 of non-array object
// in a constant expression
static_assert(my_vec.data()[2] == 3);
}
return 0;
}
Живой код: https://godbolt.org/z/u_Mgtg
(Примечание: Причина, по которой я пытаюсь обернуть значения, заключается в том, что я могу сделать option_storage , поэтому не требуется T
для конструирования по умолчанию)