Mik*_*ail 30 c++ arrays constexpr c++14
我正在尝试使用给定的函数在编译时填充2D数组.这是我的代码:
template<int H, int W>
struct Table
{
int data[H][W];
//std::array<std::array<int, H>, W> data; // This does not work
constexpr Table() : data{}
{
for (int i = 0; i < H; ++i)
for (int j = 0; j < W; ++j)
data[i][j] = i * 10 + j; // This does not work with std::array
}
};
constexpr Table<3, 5> table; // I have table.data properly populated at compile time
Run Code Online (Sandbox Code Playgroud)
它运行得很好,table.data在编译时正确填充.
然而,如果我改变普通2D阵列int[H][W]与std::array<std::array<int, H>, W>我有在循环体中的错误:
error: call to non-constexpr function 'std::array<_Tp, _Nm>::value_type& std::array<_Tp, _Nm>::operator[](std::array<_Tp, _Nm>::size_type) [with _Tp = int; long unsigned int _Nm = 3ul; std::array<_Tp, _Nm>::reference = int&; std::array<_Tp, _Nm>::value_type = int; std::array<_Tp, _Nm>::size_type = long unsigned int]'
data[i][j] = i * 10 + j;
^
Compilation failed
Run Code Online (Sandbox Code Playgroud)
显然,我试图调用非常量重载std::array::operator[],而不是constexpr.问题是,为什么不constexpr呢?如果C++ 14允许我们修改在constexpr范围内声明的变量,为什么不支持std::array?
我曾经认为这std::array就像普通阵列一样,只是更好.但这是一个例子,我可以使用普通数组,但不能使用std::array.
Mik*_*ail 27
好吧,这确实是标准的疏忽.甚至还存在一个解决这个问题的建议:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0107r0.pdf
[N3598]删除了constexpr成员函数的隐式标记为const.但是,在这次更改之后没有重新访问std :: array的成员函数,导致在std :: array的接口中对constexpr的支持出人意料.本文通过将constexpr添加到std :: array的成员函数来修复这个遗漏,该函数可以用最少量的工作来支持它.
std::array::operator[]因为C++ 14是constexpr但也是const合格:
constexpr const_reference operator[]( size_type pos ) const;
^^^^^
Run Code Online (Sandbox Code Playgroud)
因此,您必须强制转换数组以调用正确的operator[]重载:
template<int H, int W>
struct Table
{
//int data[H][W];
std::array<std::array<int, H>, W> data; // This does not work
constexpr Table() : data{} {
for (int i = 0; i < W; ++i)
for (int j = 0; j < H; ++j)
const_cast<int&>(static_cast<std::array<int, H> const&>(static_cast<std::array<std::array<int, H>, W> const&>(data)[i])[j]) = 10 + j;
}
};
Run Code Online (Sandbox Code Playgroud)
编辑:
与某些人相反,const_cast以这种方式使用并不意味着未定义的行为.事实上,正如在放宽提议中所提出的constexpr那样,用户需要进行这项工作const_cast,以便至少在C++ 17中解决问题之前唤起正确的下标操作符重载(参见链接).
虽然我的第一个想法是"为什么你需要在非const数组上使用constexpr方法"?...
然后我坐下来写了一个小测试,看看这个想法是否有意义:
#include <iostream>
using namespace std;
struct X{
constexpr X()
: _p { 0, 1, 2, 3, 4, 5, 6, 7, 9 }
{
}
constexpr int& operator[](size_t i)
{
return _p[i];
}
int _p[10];
};
constexpr int foo()
{
X x;
x[3] = 4;
return x[3];
}
auto main() -> int
{
cout << foo() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
事实证明它确实如此.
因此,我得出的结论是,委员会采取了与我所做的相同的"明显"观点,并对这一想法不屑一顾.
在我看来好像可以向委员会提交一份提案,以便在c ++ 17中对其进行更改 - 以此问题为例.