Given a template whose non-type parameter determines the size of a non-const int array member, how can I access the array elements by an integral index at compile time? I want the access to be done via the class template’s getter method at.
I figured since class templates must be instantiated before runtime, I can pass another non-type class template’s enum member value to the prior class’s at method to ensure the index argument is a compile-time constant.
I left the class template deliberate_error undefined to see if its arguments are computed at compile time and to view the compile-time results in the error messages.
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); doesn’t give an error, so I thought that if I passed the same expression to deliberate_error instance my_error2, the compiler will display the value of arr[2] in the error message.
my_error1 causes g++ error: aggregate 'deliberate_error<2u> my_error1' has incomplete type and cannot be defined,
showing cti’s wrapped integral value 2. So, I thought if I passed the same cti to object aw's getter, and then pass the result to my_error2, I can get arr[2] in the error message. But instead, it prints:
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 ';'
So, I tried prepending constexpr to aw’s declaration, but that gives even more undesirable errors. What’s wrong here, and how can I fix it?
(Note that as far as I see,
std::arraywithstd::getalready solves your problem.)The main issue is that you need your instance
awto beconstexprand of course you need to initialize it with some values:Regarding the function
at, you can write it as a normal function but simply specify it asconstexpr:Then,
aw.at(0)can be used as a constant expression: Live DemoThe advantage of this is that you can use this function in both compile-time and runtime expressions, with static and dynamic indexing, respectively.
If you really want it to be templated, you can either write it as a non-member like
std::get<N>or as a class member, but use a template parameter of typeint(orsize_tor similar). That simplifies its definition (and you can get rid of yourcompile_time_intclass template):Then,
aw.at<0>()can be used as a constant expression: Live DemoThe advantage of the second method is that the index is guaranteed to be static, so we can use it in the function for static bound checking, which will not add any performance penalty. I don't know if this is possible with the first version.