constexpr std :: initializer_list的编译时验证

时间:2018-02-08 02:40:42

标签: 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;
}

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 };

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

2 个答案:

答案 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");