我正在尝试实现一些硬编码值的编译时验证。我有以下简化尝试:
using Type = std::initializer_list<int>;
constexpr bool all_positive(const Type& list)
{
bool all_positive = true;
for (const auto& elem : list)
{
all_positive &= (elem > 0);
}
return all_positive;
}
int main()
{
static constexpr Type num_list{ 1000, 10000, 100 };
static_assert(all_positive(num_list), "all values should be positive");
return 0;
}
gcc编译它并且完全按照我的预期工作,但是clang因编译失败而错误:
static_assert_test.cc:79:16: error: static_assert expression is not an integral constant expression
static_assert(all_positive(num_list), "all values should be positive");
^~~~~~~~~~~~~~~~~~~~~~
static_assert_test.cc:54:20: note: read of temporary is not allowed in a constant expression outside the expression that created the temporary
all_positive &= (elem > 0);
^
static_assert_test.cc:79:16: note: in call to 'all_positive(num_list)'
static_assert(all_positive(num_list), "all values should be positive");
^
static_assert_test.cc:77:32: note: temporary created here
static constexpr Type num_list{ 1000, 10000, 100 };
这里的预期行为是什么?这应该编译吗?如果没有,是否有另一种方法来验证硬编码值?
答案 0 :(得分:3)
正如Yola的回答所说,创建了一个临时数组,表达式elem > 0
尝试将左值到右值的转换应用于elem
。现在我们引用标准[expr.const]/2:
表达式e是核心常量表达式,除非根据抽象机器的规则评估e将评估以下表达式之一:
...
左值到左值的转换,除非它应用于
整数或枚举类型的非易失性glvalue,它引用一个完整的非易失性const对象,具有前面的初始化,用常量表达式初始化,或者
一个非易失性glvalue,它引用字符串文字的子对象,或
非易失性glvalue,引用用
constexpr
定义的非易失性对象,或引用此类对象的不可变子对象,或文字类型的非易失性glvalue,引用一个非易失性对象,其生命周期始于e的评估范围内;
...
请注意,第一个项目符号不适用于此处,因为elem
未引用完整对象(它是数组的子对象)。第三个项目符号也不适用,因为临时数组没有用constexpr
定义,尽管它是一个const对象。结果,all_positive(num_list)
无法成为常量表达式。
关键是在常量表达式中不允许访问const的元素而不是constexpr
数组,尽管这些元素的值可能可以确定在编译时。以下代码段显示了此问题:
const int ci[1] = {0};
const int &ri = ci[0];
constexpr int i = ri; // error
答案 1 :(得分:2)
问题是您正在尝试使用临时数组初始化constexpr
。
std :: initializer_list类型的对象是从初始化列表构造的,就像实现一样 生成并实现(7.4)“N const E”数组的prvalue,其中N是元素的数量 在初始化列表中。
但是这个临时数组本身并不是一个常量。它可以像这样工作:
static constexpr array<int,4> arr = { 1000, 10000, 100 };
static constexpr Type num_list(&arr[0], &arr[3]);
static_assert(all_positive(num_list), "all values should be positive");