constexpr隐含noexcept吗? [英] Does constexpr imply noexcept?

查看:103
本文介绍了constexpr隐含noexcept吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

constexpr 说明符是否暗示函数的 noexcept 说明符?回答简单检查显示出它的答案.并非如此.

  constexpr布尔f(int)noexcept{返回true;}constexpr布尔g(int){返回true;}static_assert(noexcept(f(1)));static_assert(noexcept(g(2)));//注释此行以检查运行时行为#include< cassert>#include< cstdlib>整型main(int argc,char * []){断言(noexcept(f(argc)));assert(noexcept(g(argc)));返回EXIT_SUCCESS;} 

解决方案

不是这样,因为并非每次对constexpr函数的调用都必须被评估为核心常量表达式的子表达式.我们只需要一个允许这样做的参数值.因此,只要我们具有不调用该分支的参数值,constexpr函数就可以包含 throw 语句.

这在C ++ 14标准草案草稿中 7.1.5 constexpr说明符[dcl.constexpr]告诉我们constexpr函数中允许的内容:

constexpr函数的定义应满足以下约束:

  • 它不能是虚拟的(10.3);

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

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

  • 其功能主体应为= delete,= default或不包含的复合语句

    • asm定义

    • goto语句

    • 尝试块,或

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

我们看到的

并不禁止 throw ,实际上自

成为( 将其与gcc一起使用 ):

  01个 

通过 webcompiler

Visual Studio也会产生相同的结果.如hvd所述,clang有一个bug,如错误报告 noexcept所记录,应检查表达式是否为一个常量表达式.

缺陷报告1129

缺陷报告1129:constexpr函数的默认nothrow 提出相同的问题:

不允许constexpr函数通过异常返回.应该认识到这一点,并且在没有显式异常规范的情况下声明为constexpr的函数应视为声明为noexcept(true)而不是通常的noexcept(false).对于没有显式异常说明的声明为constexpr的函数模板,当且仅当在给定实例中使用constexpr关键字时,才应将其视为noexcept(true).

,回复为:

前提不正确:仅当在需要常量表达式的上下文中调用constexpr函数时,才禁止异常.用作普通函数,它可以抛出.

并修改了5.3.7 [expr.unary.noexcept]第3段第1项(强调强调的其他内容):

对不具有非抛出异常规范(15.4 [except.spec])的函数,成员函数,函数指针或成员函数指针的可能评估的调用80,除非该调用为常量表达式(5.20 [expr.const]),

Does constexpr specifier imply noexcept specifier for a function? Answer to the similar question says "yes" concerning inline specifier, but Eric Niebler's article makes me wonder about possible answer to the current one. On my mind answer can depends on context of a using a constexpr function: is it constant expression context or run-time context, i.e. are all the parameters of the function known at compile time or not.

I expected that the answer is "yes", but simple check shows that it is not the case.

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

解决方案

No this can not be the case, because not every inovocation of constexpr function has to be able to be evaluated as subexpression of a core constant expression. We only need one argument value that allows for this. So a constexpr function can contain a throw statement as long as we have a argument value which does not invoke that branch.

This is covered in the draft C++14 standard section 7.1.5 The constexpr specifier [dcl.constexpr] which tells us what is allowed in a constexpr function:

The definition of a constexpr function shall satisfy the following constraints:

  • it shall not be virtual (10.3);

  • its return type shall be a literal type;

  • each of its parameter types shall be a literal type;

  • its function-body shall be = delete, = default, or a compound-statement that does not contain

    • an asm-definition,

    • a goto statement,

    • a try-block, or

    • a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.

which as we can see does not forbid throw and in fact forbids very little since the Relaxing constraints on constexpr functions proposal became part of C++14.

Below we see the rule that says a constexpr function is well-formed if at least one argument value exists such that it can be evaluated as a subexpression of a core constant expression:

For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.

and below this paragraph we have the following example, which shows a perfect example for this case:

constexpr int f(bool b)
  { return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required

So we would expect the output for the following example:

#include <iostream>

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

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

to be (see it live with gcc):

 0
 1

Visual Studio via webcompiler also produces the same result. As hvd noted, clang has a bug as documented by the bug report noexcept should check whether the expression is a constant expression.

Defect Report 1129

Defect report 1129: Default nothrow for constexpr functions asks the same question:

A constexpr function is not permitted to return via an exception. This should be recognised, and a function declared constexpr without an explicit exception specification should be treated as if declared noexcept(true) rather than the usual noexcept(false). For a function template declared constexpr without an explicit exception specification, it should be considered noexcept(true) if and only if the constexpr keyword is respected on a given instantiation.

and the response was:

The premise is not correct: an exception is forbidden only when a constexpr function is invoked in a context that requires a constant expression. Used as an ordinary function, it can throw.

and it modified 5.3.7 [expr.unary.noexcept] paragraph 3 bullet 1 (addition noted with emphasis):

a potentially evaluated call80 to a function, member function, function pointer, or member function pointer that does not have a non-throwing exception-specification (15.4 [except.spec]), unless the call is a constant expression (5.20 [expr.const]),

这篇关于constexpr隐含noexcept吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆