给定一个模板,其非类型参数确定非const int
数组成员的大小,如何在编译时通过整数索引访问数组元素?我希望通过类模板的getter方法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
会导致g ++ error: aggregate 'deliberate_error<2u> my_error1' has incomplete type and cannot be defined
,
显示cti
的包装整数值2
。所以,我想如果我将相同的cti
传递给对象aw
的getter,然后将结果传递给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
的声明中,但这会产生更多不良错误。这里有什么问题,我该如何解决?
答案 0 :(得分: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;
答案 1 :(得分:2)
(请注意,据我所知,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
的模板参数(或{{ 1}}或类似的)。这简化了它的定义(你可以摆脱你的size_t
类模板):
compile_time_int
然后,template<int Index>
constexpr int const& at() const {
return arr[Index];
}
可用作常量表达式:Live Demo
第二种方法的优点是保证索引是静态的,因此我们可以在函数中使用它进行静态边界检查,这不会增加任何性能损失。我不知道第一个版本是否可行。