【发布时间】:2016-03-24 03:17:17
【问题描述】:
已知std::array::operator[],因为C++14是constexpr,见下面的声明:
constexpr const_reference operator[]( size_type pos ) const;
不过,它也是const 合格的。如果您想使用 std::array 的下标运算符以便在编译时将值分配给您的数组,这会产生影响。例如考虑以下用户文字:
template<typename T, int N>
struct FooLiteral {
std::array<T, N> arr;
constexpr FooLiteral() : arr {} { for(int i(0); i < N; ++i) arr[i] = T{42 + i}; }
};
如果您尝试声明类型为FooLiteral 的constexpr 变量,上述代码将无法编译。这归因于重载决策规则将数组下标运算符的非 const 限定、非 constexpr 重载限定为更好的匹配。因此编译器抱怨调用非constexpr 函数。
我不知道委员会将这个重载声明为符合 C++14 条件的 const 的原因是什么,但似乎暗示正在引起注意,还有一个建议 p0107R0 来修复this 在即将到来的 C++17 中。
我很自然地为 C++14 克服了这个问题,就是以某种方式破解表达式,以唤起正确的下标运算符。我所做的如下:
template<typename T, int N>
struct FooLiteral {
std::array<T, N> arr;
constexpr FooLiteral() : arr {} {
for(int i(0); i < N; ++i) {
const_cast<T&>(static_cast<const std::array<T, N>&>(arr)[i]) = T{42 + i};
}
}
};
也就是说,我将数组转换为 const 引用以唤起正确的下标运算符重载,然后我将 const_cast 重载的下标运算符的返回对象转换为 T& 以删除其 const-ness 并能够分配给它。
这很好用,但我知道应该谨慎使用const_cast,坦率地说,我对这种黑客行为是否会导致未定义的行为有了第二个想法。
直觉上,我认为没有问题,因为这个const_cast 是在编译时初始化时发生的,因此我想不出在这种状态下会出现什么暗示。
但是是这样吗,还是我错了,这将 UB 引入了程序?
问:
有人可以证明这是否是 UB 吗?
【问题讨论】:
标签: c++ c++14 undefined-behavior constexpr const-cast