constexpr函数允许什么?

Jon*_*Mee 13 c++ function constexpr c++14 c++17

constexpr函数不应包含:

非文字类型变量的定义

但是在这个答案中,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;
    }();
}
Run Code Online (Sandbox Code Playgroud)

在我的评论中,我定义了div_t一个:如何初始化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;
}
Run Code Online (Sandbox Code Playgroud)

究竟是什么意思禁止"非字面型变量的定义"?

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

Jon*_*Mee 17

几乎可以保证,如果存在差异,gcc具有正确的行为,因为Visual Studio 2015不支持的扩展constexpr:https://msdn.microsoft.com/en-us/library/hh567368.aspx #C-14核心,语言的功能

C++ 11 constexpr函数

函数体只能包含:

  • 空语句(普通分号)
  • static_assert 声明
  • typedef 声明和别名声明,不定义类或枚举
  • using 声明
  • using 指令
  • 一个return陈述

所以不能容忍定义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};
}
Run Code Online (Sandbox Code Playgroud)

Live Example

C++ 14 constexpr函数

函数体可能包含以下任何内容:

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

其中"文本类型"的定义在这里不过,具体的对象,他们可能聚合类型有一个平凡的析构函数.所以div_t绝对有资格.因此,和扩展gcc可以容忍定义decltype(div(T{}, T{})) x{}.

C++ 17的constexpr功能

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

[ 来源 ]