我想使用constexpr填充一个枚举数组.阵列的内容遵循某种模式.
我有一个枚举将ASCII字符集分为四类.
enum Type {
Alphabet,
Number,
Symbol,
Other,
};
constexpr Type table[128] = /* blah blah */;
Run Code Online (Sandbox Code Playgroud)
我想有一个128的数组Type.它们可以是一个结构.数组的索引将对应于ASCII字符,值将是Type每个字符的值.
所以我可以查询这个数组,找出ASCII字符属于哪个类别.就像是
char c = RandomFunction();
if (table[c] == Alphabet)
DoSomething();
Run Code Online (Sandbox Code Playgroud)
我想知道如果没有一些冗长的宏观黑客,这是否可行.
目前,我通过执行以下操作来初始化表.
constexpr bool IsAlphabet (char c) {
return ((c >= 0x41 && c <= 0x5A) ||
(c >= 0x61 && c <= 0x7A));
}
constexpr bool IsNumber (char c) { /* blah blah */ }
constexpr bool IsSymbol (char c) { /* blah blah */ } …Run Code Online (Sandbox Code Playgroud) 作为在讨论这个SO问题时提出的一个问题:
申报对象是否合法,可能是N3471constexpr std::initializer_list?例:
constexpr std::initializer_list<int> my_list{};
Run Code Online (Sandbox Code Playgroud)
为什么我认为它可能不合法:initializer_list必须是字面类型; 但有没有保证它是文字类型?
来自N3485的引文.
[dcl.constexpr]/9:
对象声明中使用的constexpr说明符将对象声明为const.这样的对象应具有文字类型并应初始化.
文字类型要求,[basic.types]/10,子项目类类型:
- 具有以下所有属性的类类型(第9节):
- 它有一个简单的析构函数,
- 非静态数据成员(如果有)的brace-or-equal-initializers中的每个构造函数调用和完全表达式都是一个常量表达式(5.19),
- 它是一个聚合类型(8.5.1)或者至少有一个constexpr构造函数或构造函数模板,它不是复制或移动构造函数,并且
- 它的所有非静态数据成员和基类都是非易失性文字类型.
奖励积分;)用于回答if
constexpr std::initializer_list<int> my_list = {1,2,3,4,5};
Run Code Online (Sandbox Code Playgroud)
是合法的(有参考).虽然我认为上述+ [dcl.init.list]/5涵盖了这一点
很长一段时间,gcc一直在提供许多内置的bit-twiddling函数,特别是尾随和前导0位的数量(也用于long unsigned和long long unsigned,有后缀l和ll):
- 内置功能:
int __builtin_clz (unsigned int x)
x从最高有效位开始返回前导0位的数量.如果x为0,则结果未定义.- 内置功能:
int __builtin_ctz (unsigned int x)
x从最低有效位开始返回尾随0位的数量.如果x为0,则结果未定义.
在每一个在线(免责声明:仅64位)编译器,我测试,然而,结果是,无论clz(0)和ctz(0)返回底层内建类型,例如位的数目
#include <iostream>
#include <limits>
int main()
{
// prints 32 32 32 on most systems
std::cout << std::numeric_limits<unsigned>::digits << " " << __builtin_ctz(0) << " " << __builtin_clz(0);
}
Run Code Online (Sandbox Code Playgroud)
实例.
在最新的锵SVN主干std=c++1y模式取得了所有这些功能放宽C++ 14 constexpr,这使得它们的候选在SFINAE表达式以用于围绕3包装函数模板 …
在类定义中初始化静态整型数据成员可以声明const或constexpr,但在类定义中初始化非整数的静态数据成员必须是constexpr:
class MyClass {
static const int w = 5; // okay
static constexpr int x = 5; // okay
static const float y = 1.5; // error!
static constexpr float z = 1.5; // okay
};
Run Code Online (Sandbox Code Playgroud)
有人知道为什么不允许y的声明吗?标准中将其定为非法的部分是9.4.2/3,但为什么它是非法的?
当您尝试使用constexpr时,main如下所示:
constexpr int main()
Run Code Online (Sandbox Code Playgroud)
gcc和clang抱怨:
错误:无法声明':: main'为内联
错误:'main'不允许声明为constexpr
让我们看看constexpr函数的要求是什么:
constexpr函数必须满足以下要求:
什么是LiteralType?
文字类型是以下任何一种
功能主体必须包括什么?
以下示例:
constexpr int main() { ; }
constexpr int main() { return 42; }
constexpr int main() {
// main defaults to return 0
}
Run Code Online (Sandbox Code Playgroud)
似乎符合所有这些要求.还有这个,main是在程序开始之前运行的特殊功能.您可以从main运行constexpr函数,并且为了将constexpr标记为constexpr,它必须在constexpr上下文中运行.
那么为什么main不允许成为constexpr?
当constexpr在C++ 11中引入时,我很兴奋,但遗憾的是我对其有用性做出了乐观的假设.我假设我们可以在任何地方使用constexpr来捕获文字编译时常量或文字编译时常量的任何constexpr结果,包括这样的事情:
constexpr float MyMin(constexpr float a, constexpr float b) { return a<b?a:b; }
Run Code Online (Sandbox Code Playgroud)
因为仅将函数的返回类型限定为constexpr并不将其使用限制为编译时,并且还必须在运行时可调用,所以我认为这将是确保MyMin只能与编译时计算的常量一起使用的一种方法,这将确保编译器永远不会允许它在运行时执行,让我可以编写另一个更加运行时友好的MyMin版本,理想情况下使用相同名称使用_mm_min_ss内在函数,确保编译器不会生成运行时分支码.不幸的是,函数参数不能是constexpr,所以似乎无法做到这一点,除非这样的事情是可能的:
constexpr float MyMin(float a, float b)
{
#if __IS_COMPILE_TIME__
return a<b?a:b;
#else
return _mm_cvtss_f32(_mm_min_ss(_mm_set_ss(a),_mm_set_ss(b)));
#endif
}
Run Code Online (Sandbox Code Playgroud)
我严重怀疑MSVC++有这样的东西,但是我希望GCC或者clang至少有一些东西可以实现它,不管它看起来有多么不优.
当然,我提供的示例非常简单,但是如果你可以运用你的想象力,在很多情况下你可以随意做一些事情,比如在一个你知道只能在编译时执行的函数中广泛使用分支语句,因为如果它在运行时执行,性能会受到影响.
假设我有一个类X,哪个功能需要很多常量表值,比如一个数组A[1024].我有一个f计算其值的重复函数,就像
A[x] = f(A[x - 1]);
Run Code Online (Sandbox Code Playgroud)
假设这A[0]是一个已知常量,因此数组的其余部分也是常量.使用现代C++的功能预先计算这些值的最佳方法是什么,并且没有使用此数组的硬编码值存储文件?我的解决方法是一个const静态虚拟变量:
const bool X::dummy = X::SetupTables();
bool X::SetupTables() {
A[0] = 1;
for (size_t i = 1; i <= A.size(); ++i)
A[i] = f(A[i - 1]);
}
Run Code Online (Sandbox Code Playgroud)
但我相信,这不是最美好的方式.注意:我强调数组相当大,我想避免代码的怪异.
我可以在头文件中有这样的定义吗?
constexpr double PI=3.14;
Run Code Online (Sandbox Code Playgroud)
在包含在几个cpp文件中的头文件中有这个问题吗?
我担心,因为它在标准中说这个constexpr有自己的内存,把它放在头文件中,并在几个cpp文件中添加标题,在内存中生成相同值的多个副本以及其他一些令人讨厌的问题.
我正在使用C++ 11
为什么constexpr函数在编译时没有被评估,而是在main函数的return语句中运行时?
它试过了
template<int x>
constexpr int fac() {
return fac<x - 1>() * x;
}
template<>
constexpr int fac<1>() {
return 1;
}
int main() {
const int x = fac<3>();
return x;
}
Run Code Online (Sandbox Code Playgroud)
结果是
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 6
mov eax, 6
pop rbp
ret
Run Code Online (Sandbox Code Playgroud)
与gcc 8.2.但是当我在return语句中调用该函数时
template<int x>
constexpr int fac() {
return fac<x - 1>() * x;
}
template<>
constexpr int fac<1>() {
return 1;
}
int main() {
return fac<3>(); …Run Code Online (Sandbox Code Playgroud) 为什么下面的代码没有编译?
// source.cpp
int main()
{
constexpr bool result = (0 == ("abcde"+1));
}
Run Code Online (Sandbox Code Playgroud)
编译命令:
$ g++ -std=c++14 -c source.cpp
Run Code Online (Sandbox Code Playgroud)
输出:
source.cpp: In function ‘int main()’:
source.cpp:4:32: error: ‘((((const char*)"abcde") + 1u) == 0u)’ is not a constant expression
constexpr bool result = (0 == ("abcde"+1));
~~~^~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
我正在使用gcc6.4.
c++ ×10
constexpr ×10
c++11 ×6
c++14 ×3
c++17 ×2
gcc ×2
clang ×1
compile-time ×1
precompile ×1
templates ×1