2015-12-14 119 views
7

例如下面的代码不编译除非incr()被声明constexpr在C++ 14标准中,它是否说非constexpr函数不能用于constexpr函数的定义?

int incr(int& n) { 
    return ++n; 
} 

constexpr int foo() { 
    int n = 0; 
    incr(n); 
    return n; 
} 

在C++ 14在§7.1.5/ 3寻找我们有:

的定义constexpr函数应该满足以下约束:
(3.1) - 它不应该是虚拟的(10.3);
(3.2) - 它的返回类型应该是一个文字类型;
(3.3) - 它的每个参数类型应该是一个文字类型;
(3.4) - 其功能体应为=删除,=默认情况下,或不包含

(3.4.1)的化合物语句 - 一个ASM清晰度,
(3.4.2) - goto语句,
(3.4.3) - 一个try-block,或者
(3.4.4) - 一个变量的定义非文字类型或静态或线程存储持续时间或其中 无初始化被执行。

+0

也许值得指出的[前面的问题](http://stackoverflow.com/q/34211688/1708801),其覆盖了许多相同的地,尽管从不同的角度。 –

+0

@ShafikYaghmour我真的很感激你对这个新问题的评论。 – Ayrosa

+0

请注意,你所引用的内容是必要的*但不是充分*的条件,即如果这些条件被违反,那么代码是不合格的,但是如果他们没有违反,那么代码可能会或可能不会是正确的,我们必须查看规范的其他部分。 –

回答

10

两段后,在[dcl.constexpr]/5:

对于非模板,非缺省constexpr功能或非模板,非默认,非继承 constexpr构造函数,如果不存在任何参数值,以便函数或构造函数的调用可以是核心常量表达式(5.20)的评估子表达式,或者对于某个对象(3.6.2)的构造函数,常量 初始值设定项, ,该方案是不健全的;不需要诊断。

无参数存在,使得foo()可以是芯常量表达式由于incr(),因此程序是形成不良的(NDR)。

+0

我不认为§7.1.5/ 5与这个问题无关。例如,在标准中,它是否表示constexpr函数的主体必须是核心常量表达式? – Ayrosa

+0

@Ayrosa:就在那里。 “函数或构造函数的调用可以是核心常量表达式的一个评估子表达式”但它不是必须的整个身体,只是评估的部分。 –

+0

@BenVoigt但是,它并没有说constexpr函数的主体是核心常量表达式。 – Ayrosa

4

它没有。

下是允许的,即使它你猜测什么是被禁止的:

int incr(int& n) { 
    return ++n; 
} 

constexpr int foo(bool x) { 
    int n = 0; 
    if (x) incr(n); 
    return n; 
} 

在你的问题中的代码是通过与巴里的规则不允许援引他的回答。但是在我的变体中,确实存在一组参数(具体地说,false),调用foo会导致编译时常量表达式。

请注意,诊断不是必需的 - 符合的编译器也可以允许您的版本进行编译。

+1

值得注意的是,g ++无法编译两个版本,在这两种情况下给出相同(不正确)的错误消息。铿锵++汇编这一个,并拒绝原始的,引用正确的原因:“constexpr函数永远不会产生一个常量表达式”。 –

+1

@ n.m。这个bug在gcc中已经修复 – bames53

+0

我花了一段时间才真正体会到了答案,你的和bames53的(+1)的质量。 – Ayrosa

8

什么你要找的是§5.19:

一个条件表达式Ë是一个核心的常量表达式,除非Ë的评价,以下抽象机的规则( 1。9)将评估以下表达式之一:

这适用于对函数调用constexpr表达式的评估。也就是说,调用constexpr函数将是一个'核心常量表达式',如果评估函数,即根据C++抽象机器的规则执行函数主体,则不会执行给定列表中禁止的任何事情在第5.19节中。

一个列表中的项目是:

  • 功能比[...]一个constexpr功能以外的调用

所以申请到您的示例:评估表达式foo()评估对函数incr()的调用,该函数不是constexpr函数,这意味着表达式foo()不是核心常量表达式。此外,由于上述适用于函数foo的所有可能调用,第7.1.5节/5.5节中的规则开始,并且意味着您的示例程序不合格,不需要诊断,即使您从不使用实际上拨打foo()


由于本福格特指出一个constexpr函数可以包含非consexpr函数的调用,只要函数的具体评价实际上并不评价任何这样的函数调用(或它出现在,做一个上下文不需要一个常量表达式)。

5.19中的限制仅与表达式评估的一部分实际上最终被评估的表达式有关。

例如:

#include <iostream> 

int incr(int &n) { return ++n; } 

enum E {be_constexpr, not_constexpr}; 

constexpr int foo(E e = be_constexpr) { 
    int n = 0; 
    if (e == not_constexpr) { incr(n); } 
    return n; 
} 

int main() { 
    constexpr int a = foo(); // foo() is a constant expression 
    int b = foo(not_constexpr); // may or may not evaluate `foo(non_constexpr)` at runtime. In practice modern C++ compilers will do compile-time evaluation here even though they aren't required to. 
    // constexpr int c = foo(not_constexpr); // Compile error because foo(not_constexpr) is not formally a constant expression, even though modern compilers can evaluate it at compile-time. 

    std::cout << a << ' ' << b << '\n'; 
} 
+0

我花了一段时间才真正体会到你的答案和本Voigt(+1)的质量。 – Ayrosa

相关问题