constexpr函数允许什么?

时间:2017-01-12 16:43:20

标签: c++ function c++14 constexpr c++17

constexpr functions不应包含:

  

非文字类型

变量的定义

但在这个答案中,lambda定义在一个:https://stackoverflow.com/a/41616651/2642059

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    return [&]() {
        decltype(std::div(quot, rem)) result;
        result.quot = quot;
        result.rem = rem;
        return result;
    }();
}

在我的评论中,我在一个How can I Initialize a div_t Object?

中定义了div_t
template <typename T>
constexpr decltype(div(T{}, T{})) make_div(const T quot, const T rem)
{
    decltype(div(T{}, T{})) x{};
    x.quot = quot;
    x.rem = rem;
    return x;
}

禁止对非文字类型的变量进行定义&#34;究竟是什么意思?

Visual Studio 2015不允许我对div_t的定义,但我发现在lambda中包含这些非法行为并执行它是不允许的。我想知道哪一个编译器在div_t定义方面表现正常。

1 个答案:

答案 0 :(得分:15)

几乎可以保证,如果存在差异,gcc具有正确的行为,因为Visual Studio 2015不支持constexpr的{​​{1}}扩展:

C ++ 11 constexpr函数

函数体只能 包含:

  
      
  • null语句(普通分号)
  •   
  • static_assert声明
  •   
  • typedef声明和不定义类或枚举的别名声明
  •   
  • using声明
  •   
  • using指令
  •   
  • 恰好一个return声明
  •   

因此https://msdn.microsoft.com/en-us/library/hh567368.aspx#C-14-Core-Language-Features无法容忍decltype(div(T{}, T{})) x{}的定义。然而,在constexpr函数中推荐三元建议以获得相同的结果是可以接受的:

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    using foo = decltype(div(T{}, T{}));

    return foo{1, 0}.quot != 0 ? foo{quot, rem} : foo{rem, quot};
}

here

C ++ 14 constexpr函数

函数体可能包含之外的任何内容:

  
      
  • asm声明
  •   
  • 一个转到声明
  •   
  • 带有除case和default之外的标签的声明
  •   
  • 试用块
  •   
  • 非文字类型变量的定义
  •   
  • 静态或线程存储持续时间变量的定义
  •   
  • 未执行初始化的变量的定义
  •   

如果定义了“文字类型”Live Example,特别是对于对象,它们可能是具有普通析构函数的聚合类型。所以div_t绝对有资格。因此,here和扩展名gcc可以容忍decltype(div(T{}, T{})) x{}的定义。

C ++ 17 constexpr函数

C ++ 17在“Literal Type”的定义中添加了对闭包类型的支持,所以我觉得奇怪的是gcc和Visual Studio都支持在return语句中使用lambda。我想这是前瞻性支持或编译器选择内联lambda。在任何一种情况下,我认为它不符合 constexpr函数。

[]