Mar*_*tto 7 c++ language-lawyer constant-expression
考虑以下功能:
template <size_t S1, size_t S2>
auto concatenate(std::array<uint8_t, S1> &data1, std::array<uint8_t, S2> &data2) {
std::array<uint8_t, data1.size() + data2.size()> result;
auto iter = std::copy(data1.begin(), data1.end(), result.begin());
std::copy(data2.begin(), data2.end(), iter);
return result;
}
int main()
{
std::array<uint8_t, 1> data1{ 0x00 };
std::array<uint8_t, 1> data2{ 0xFF };
auto result = concatenate(data1, data2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当使用clang 6.0编译时,使用-std = c ++ 17,此函数无法编译,因为数组上的size成员函数不是constexpr,因为它是一个引用.错误消息是这样的:
错误:非类型模板参数不是常量表达式
当参数不是引用时,代码按预期工作.
我想知道为什么会这样,因为size()实际上返回一个模板参数,它几乎不再是const.参数是否是参考不应该有所作为.
我知道我当然可以使用S1和S2模板参数,该功能仅仅是问题的简短说明.
标准中有什么吗?我很惊讶地发现了编译错误.
关于 clang 的此问题报告了一个错误,标题为:Clang 不允许在非类型模板参数中使用 constexpr 类型转换。
其中的讨论表明这并不是一个真正的错误。
表达式 e 是核心常量表达式,除非对 e 的求值遵循抽象机的规则,将求值以下表达式之一:
- [...]
- 引用引用类型的变量或数据成员的id 表达式,除非引用具有前面的初始化并且
- 它用常量表达式初始化或
- 它的生命周期从 e 的评估开始;
- [...]
上面的引用来自草案 n4659 的 [expr.const]/2.11,并添加了强调。
因为你已经评估了一个参考。来自[expr.const]/4:
表达式 e 是核心常量表达式,除非按照抽象机器的规则对 e 求值会求值以下表达式之一:
- ...
- 引用变量或引用类型数据成员的id 表达式,除非该引用具有前面的初始化并且
- 它可用于常量表达式或
- 它的生命周期开始于 e 的计算;
- ...
您的引用参数没有前面的初始化,因此不能在常量表达式中使用。
您可以S1 + S2在这里简单地使用。
Oli*_*liv -2
不幸的是,标准规定,在类成员访问表达式中,对点或箭头之前的后缀表达式进行求值;63 [expr.ref]/1。后缀表达式a位于a.b. 该注释非常有趣,因为这里的情况正是如此:
63) 如果对类成员访问表达式进行求值,则即使不需要结果来确定整个后缀表达式的值,也会发生子表达式求值,例如,如果 id 表达式表示静态成员。
data即使没有必要,也会对so进行求值,并且常量表达式前的规则也适用于它。
| 归档时间: |
|
| 查看次数: |
216 次 |
| 最近记录: |