Доступ во время компиляции к члену шаблона класса по индексу

Данный шаблон, чей не типовой параметр определяет размер неконстантного 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Объявление, но это дает еще больше нежелательных ошибок. Что здесь не так, и как я могу это исправить?

1

Решение

(Обратите внимание, что, насколько я вижу, 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

Преимущество второго метода заключается в том, что индекс гарантированно является статическим, поэтому мы можем использовать его в функции для статической проверки границ, что не приведет к снижению производительности. Я не знаю, возможно ли это с первой версией.

2

Другие решения

Может быть только это:

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;
2

По вопросам рекламы [email protected]