Данный шаблон, чей не типовой параметр определяет размер неконстантного int
член массива, как я могу получить доступ к элементам массива по интегральному индексу во время компиляции? Я хочу, чтобы доступ был сделан с помощью метода get шаблона класса at
,
Я подумал, так как шаблоны классов должны быть созданы до выполнения, я могу передать другой шаблон не типового класса enum
значение члена для предыдущего класса at
метод обеспечения index
Аргумент — это константа времени компиляции.
Я оставил шаблон класса deliberate_error
неопределенный, чтобы видеть, вычисляются ли его аргументы во время компиляции и просматривать результаты времени компиляции в сообщениях об ошибках.
template <unsigned int N>
struct compile_time_int {
enum {num = N};
};
template <unsigned int N>
struct array_wrapper {
int arr[N];
template <unsigned int Ind>
constexpr int const& at(compile_time_int<Ind> const& index) const {
return arr[index.num];
}
};
template <unsigned int> struct deliberate_error;
int main() {
compile_time_int<2> cti;
array_wrapper<3> aw;
aw.at(cti);
deliberate_error<cti.num> my_error1;
deliberate_error<aw.at(cti)> my_error2;
}
aw.at(cti);
не выдает ошибку, поэтому я подумал, что если я передал то же самое выражение deliberate_error
пример my_error2
компилятор отобразит значение arr[2]
в сообщении об ошибке.
my_error1
вызывает г ++ error: aggregate 'deliberate_error<2u> my_error1' has incomplete type and cannot be defined
,
показ cti
Обернутое целое значение 2
, Итак, я подумал, если я прошел то же самое cti
для объекта aw
получатель, а затем передать результат my_error2
, Я могу получить arr[2]
в сообщении об ошибке. Но вместо этого он печатает:
error: the value of 'aw' is not usable in a constant expression
note: 'aw' was not declared 'constexpr'
note: in template argument for type 'unsigned int'
error: invalid type in declaration before ';'
Итак, я попытался предвари constexpr
в aw
Объявление, но это дает еще больше нежелательных ошибок. Что здесь не так, и как я могу это исправить?
(Обратите внимание, что, насколько я вижу, std::array
с std::get
уже решает вашу проблему.)
Основная проблема в том, что вам нужен ваш экземпляр aw
быть constexpr
и, конечно, вам нужно инициализировать его с некоторыми значениями:
constexpr array_wrapper<3> aw = { 1, 2, 3 };
По поводу функции at
Вы можете написать это как обычную функцию, но просто указать это как constexpr
:
constexpr int const& at(int i) const {
return arr[i];
}
Затем, aw.at(0)
может использоваться как константное выражение: Live Demo
Преимущество этого состоит в том, что вы можете использовать эту функцию как во время компиляции, так и во время выполнения, со статической и динамической индексацией соответственно.
Если вы действительно хотите, чтобы он был шаблонным, вы можете написать его как не член, например std::get<N>
или как член класса, но используйте параметр шаблона типа int
(или же size_t
или похожие). Это упрощает его определение (и вы можете избавиться от compile_time_int
шаблон класса):
template<int Index>
constexpr int const& at() const {
return arr[Index];
}
Затем, aw.at<0>()
может использоваться как константное выражение: Live Demo
Преимущество второго метода заключается в том, что индекс гарантированно является статическим, поэтому мы можем использовать его в функции для статической проверки границ, что не приведет к снижению производительности. Я не знаю, возможно ли это с первой версией.
Может быть только это:
template <unsigned int N>
struct array_wrapper
{
int arr[N];
};
template <unsigned int I, unsigned int N>
constexpr int & at(array_wrapper<N> & a)
{
static_assert(I < N, "static array index out of bounds");
return a.arr[I];
}
// add a "const" overload, too
Использование:
array_wrapper<10> x;
at<3>(x) = 42;