Mik*_*eMB 7 c++ language-lawyer constexpr c++11 c++14
我有以下代码:
main.cpp中
#include <cstdint>
#include <type_traits>
enum class FooEnum : uint8_t{
Foo1 = 0,
Foo2 = 1
};
constexpr uint32_t& operator|= (uint32_t& lhs, FooEnum rhs) {
return lhs |= 1u << static_cast<uint8_t>(rhs);
}
int main() {
uint32_t bar{0};
bar|=FooEnum::Foo1;
}
Run Code Online (Sandbox Code Playgroud)
基本上,|=运算符应该采用枚举并设置位,其位置对应于其整数值.
在fedora 21上用clang ++ 3.5.0编译时,一切正常,但是当用g ++ 4.9.2编译时,它会抛出一个错误,说这不是一个常量表达式:
main.cpp: In function ‘constexpr uint32_t& operator|=(uint32_t&, FooEnum)’:
main.cpp:16:2: error: expression ‘(lhs = (lhs | (1u << ((int)rhs))))’ is not a constant-expression
}
^
Run Code Online (Sandbox Code Playgroud)
对于所有类型的编译器标志组合都是如此,但是你可以测试它g++ -std=c++11 -o a.out main.cpp(c ++ 14没有区别)
所以我的问题是:
operator|=这样的g ++会接受它constexpr?编辑:
如果你想知道,为什么我试图首先声明运算符,constexpr虽然在示例中不需要:
在我的实际代码中,我使用|=-operator来实现(constexpr)|-operator,我想在constexpr表达式中使用,但在此之前,我偶然发现了两个编译器之间的区别,没有意识到,gcc4.9并不完全支持c ++ 14(尚未接受-std=c++14标记) .
当使用运算符实际初始化一个全局constexpr变量时,即使clang只用c ++ 14标志编译它.
表达lhs |= 1u << static_cast<uint8_t>(rhs)永远是常量表达式本身,因为它修改lhs.禁止在C++ 14中使用的规则是§5.19/ 2.15(在C++ 11中也存在有效的等效规则):
甲条件表达式
e是一个核心常量表达式除非的评价e,如下所述抽象机(1.9),将评估下面的表达式中的一个的规则:
- 修改对象(5.17,5.2.6,5.3.2),除非它应用于文字类型的非易失性左值,该文字类型引用一个非易失性对象,其生命周期始于评估范围内
e;
在C++ 11中,由于§7.1.5/ 5,它必须是一个:
对于
constexpr函数,如果不存在函数参数值,使得函数调用替换将产生常量表达式(5.19),则程序格式错误; 无需诊断.
在调用替换之后,不存在使返回的表达式成为常量表达式的参数:赋值可以防止这种情况发生.因此,程序在C++ 11中是不正确的(但不需要诊断),并且在编译时-std=c++11,GCC显示符合规范的行为.
在C++ 14中,该规则已经过调整:
对于非模板,非默认的
constexpr函数[...],如果不存在的参数值,使得所述函数的调用[...]可能是一个核心常量表达式(5.19)的评估子表达式,该程序是非法的构造; 无需诊断.
这使得返回表达式本身可以是非常量表达式,只要该函数可以在另一个核心常量表达式中进行求值,例如从另一个constexpr函数内部:
constexpr auto foo(FooEnum rhs)
{
uint32_t x = 0;
x |= rhs;
return x;
}
Run Code Online (Sandbox Code Playgroud)
foo(FooEnum::Foo1)是一个核心常量表达式,因此operator|=可以在核心常量表达式中调用,因此函数定义是格式良好的.
正如评论中的@dyp所述,GCC仅支持自版本5以来的"对constexpr函数的放宽约束"特性.GCC 5.1编译代码.
所以现在constexpr函数体通常由不是常量表达式的语句组成.第一个引用部分之后的示例显示了一个函数incr,GCC也会拒绝该函数:
Run Code Online (Sandbox Code Playgroud)constexpr int incr(int &n) { return ++n; } constexpr int h(int k) { int x = incr(k); // OK: incr(k) is not required to be a core // constant expression return x; }
| 归档时间: |
|
| 查看次数: |
1156 次 |
| 最近记录: |