Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ constexpr是否意味着不例外?_C++_Inline_C++14_Constexpr_Noexcept - Fatal编程技术网

C++ constexpr是否意味着不例外?

C++ constexpr是否意味着不例外?,c++,inline,c++14,constexpr,noexcept,C++,Inline,C++14,Constexpr,Noexcept,constepr说明符是否暗示函数的noexcept说明符?to对内联说明符说“是”,但让我想知道当前说明符的可能答案。在我看来,答案可能取决于使用constexpr函数的上下文:是常量表达式上下文还是运行时上下文,即编译时函数的所有参数是否已知 我原以为答案是“是”,但事实并非如此 constexpr bool f(int) noexcept { return true; } constexpr bool g(int) { return true; } static_ass

constepr
说明符是否暗示函数的
noexcept
说明符?to对
内联
说明符说“是”,但让我想知道当前说明符的可能答案。在我看来,答案可能取决于使用
constexpr
函数的上下文:是常量表达式上下文还是运行时上下文,即编译时函数的所有参数是否已知

我原以为答案是“是”,但事实并非如此

constexpr
bool f(int) noexcept
{
    return true;
}

constexpr
bool g(int)
{
    return true;
}

static_assert(noexcept(f(1)));
static_assert(noexcept(g(2))); // comment this line to check runtime behaviour

#include <cassert>
#include <cstdlib>

int
main(int argc, char * [])
{
    assert(noexcept(f(argc)));
    assert(noexcept(g(argc)));
    return EXIT_SUCCESS;
}
constexpr
boolf(int)无例外
{
返回true;
}
常量表达式
布尔g(内部)
{
返回true;
}
静态断言(noexcept(f(1));
静态断言(noexcept(g(2));//注释此行以检查运行时行为
#包括
#包括
int
main(int argc,char*[])
{
断言(noexcept(f(argc));
断言(noexcept(g(argc));
返回退出成功;
}
不例外

如果表达式包含对没有非抛出异常规范的任何类型函数的[…]调用,则结果为false,除非它是常量表达式

另外,关于
constexpr
,请注意:

noexcept运算符对于常量表达式始终返回true

在任何情况下,它似乎都不意味着
constepr
说明符强制为所包围的表达式指定
noexcept
说明符,正如有人在注释中用反例所示,您也验证了这一点

无论如何,从文档中,有以下关于
noexcept
constexpr
之间关系的有趣注释:

由于noexcept运算符始终为常量表达式返回true,因此可以使用它检查constexpr函数的特定调用是否采用常量表达式分支

编辑:带有GCC的示例

感谢@hvd对GCC关于我上一次报价的有趣评论/示例

constexpr int f(int i) {
    return i == 0 ? i : f(i - 1);
}

int main() {
    noexcept(f(512));
    return noexcept(f(0)) == noexcept(f(0));
}
上面的代码返回
0
,并警告语句
noexcept(f(512))
无效。
注释掉假定无效的语句后,返回值变为
1

编辑:已知的叮当声bug

再次感谢@hvd也提供了link,这是关于问题中提到的代码的一个众所周知的bug

从错误报告中引用:

<>〈C++〉,[第1章除外] P3:

“如果在可能求值的上下文中,表达式将包含对没有非抛出异常规范(15.4)的函数、成员函数、函数指针或成员函数指针的可能求值调用,则noexcept运算符的结果为false,除非该调用是常量表达式(5.19)”

我们不执行最后一句话


不,一般来说不是

可以在允许抛出异常的非constepr上下文中调用constexpr函数(当然,手动将其指定为
noexcept(true)

但是,作为常量表达式的一部分(例如在您的示例中),它的行为应该像指定为
noexcept(true)
(当然,如果表达式的求值将导致抛出异常,这不会导致调用
std::terminate
,因为程序尚未运行,而是会导致编译时错误)


正如我所料,您的示例不会触发MSVC和g++的静态断言。我不确定这是clang中的错误还是我对标准中的某些内容理解错误。

您可以在constexpr函数中抛出异常。它的设计是这样的,以便实现者可以向编译器指示错误请考虑以下功能:

constexpr int fast_sqrt(int x) {
    return (x < 0) ? throw invalid_domain() : fast_sqrt_impl(x);
}
constexpr int fast\u sqrt(int x){
返回(x<0)?抛出无效的\u域():fast\u sqrt\u impl(x);
}
在这种情况下,如果x为负值,我们需要立即停止编译,并通过编译器错误向用户指出问题。这遵循了编译器错误优于运行时错误(快速失败)的思想

C++标准在(5.20)中说明了这一点:

条件表达式e是一个核心常量表达式,除非根据 抽象机器(1.9)将计算以下表达式之一:

-投掷表情(5.17)


不,这是不可能的,因为不是constexpr函数的每一个inovocation都必须能够作为核心常量表达式的子表达式进行计算。我们只需要一个参数值就可以实现这一点。因此,只要有一个不调用该分支的参数值,constexpr函数就可以包含一个throw语句

C++14标准草案部分
7.1.5
constexpr说明符[dcl.constexpr]介绍了这一点,它告诉我们在constexpr函数中允许什么:

constexpr int fast_sqrt(int x) {
    return (x < 0) ? throw invalid_domain() : fast_sqrt_impl(x);
}
constexpr函数的定义应满足以下约束条件:

  • 它不应是虚拟的(10.3)

  • 其返回类型应为文字类型

  • 其每个参数类型应为文字类型

  • 其函数体应为=delete、=default或不包含

    • asm定义

    • goto声明

    • 试块,或

    • 非文字类型变量或静态或线程存储持续时间变量的定义,或 不执行初始化

正如我们所看到的,这并不禁止抛出,事实上,自从提案成为C++14的一部分以来,几乎没有禁止

下面我们看到的规则是,如果至少有一个参数值存在,那么constexpr函数的格式是正确的,这样它就可以作为子表达式进行计算
#include <iostream>

constexpr int f(bool b)   { return b ? throw 0 : 0; } 

int main() {
    std::cout << noexcept( f(1) ) << "\n" 
              << noexcept( f(0) ) << "\n" ; 
}
 0
 1