constexpr std :: initializer_list的编译时验证

Joh*_*qua 12 c++ c++14

我正在尝试实现一些硬编码值的编译时验证.我有以下简化尝试:

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;
}
Run Code Online (Sandbox Code Playgroud)

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 };
Run Code Online (Sandbox Code Playgroud)

这里的预期行为是什么?这应该编译吗?如果没有,是否有另一种方法来验证硬编码值?

xsk*_*xzr 3

正如 Yola 的回答所说,创建了一个临时数组,并且表达式elem > 0尝试将左值到右值转换应用于elem. 现在我们参考标准[expr.const]/2

表达式 e 是核心常量表达式,除非对 e 的求值遵循抽象机的规则,将求值以下表达式之一:

  • ...

  • 左值到右值的转换,除非它应用于

    • 整型或枚举类型的非易失性泛左值,引用具有前面初始化的完整非易失性 const 对象,并使用常量表达式进行初始化,或者

    • 引用字符串文字的子对象的非易失性泛左值,或者

    • 一个非易失性泛左值,它引用用 定义的非易失性对象constexpr,或者引用此类对象的非可变子对象,或者

    • 文字类型的非易失性泛左值,指的是其生命周期开始于 e 求值期间的非易失性对象;

  • ...

请注意,第一个项目符号在这里不适用,因为它elem不引用完整的对象(它是数组的子对象)。第三个项目符号也不适用,因为临时数组constexpr虽然是 const 对象,但未定义。结果,all_positive(num_list)未能成为常量表达式。

关键是constexpr在常量表达式中不允许访问 const 的元素,但不允许访问数组的元素,尽管这些元素的值可以在编译时确定。下面的代码片段显示了这个问题:

const int ci[1] = {0};
const int &ri = ci[0];
constexpr int i = ri; // error
Run Code Online (Sandbox Code Playgroud)