Mir*_*pas 86 c++ standards string-literals constexpr c++11
我正在尝试在编译时计算字符串文字的长度.为此,我使用以下代码:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Run Code Online (Sandbox Code Playgroud)
一切都按预期工作,程序打印4和8.由clang生成的汇编代码显示结果在编译时计算:
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl $0x4, %esi
0x100000f6a: movl $0x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
Run Code Online (Sandbox Code Playgroud)
我的问题:标准是否保证length
函数将在编译时进行评估?
如果这是真的,编译时字符串文字计算的大门刚刚为我打开...例如,我可以在编译时计算哈希值等等......
Sha*_*our 69
不保证在编译时计算常量表达式,我们只有草案C++标准部分5.19
常量表达式的非规范性引用,但是这样说:
[...]> [注意:在翻译过程中可以评估常量表达式.-end note]
您可以将结果分配给constexpr
变量以确保在编译时对其进行求值,我们可以从Bjarne Stroustrup的C++ 11参考中看到这一点(强调我的):
除了能够在编译时计算表达式之外,我们还希望能够在编译时要求表达式进行求值; 变量定义前面的constexpr就是这样(并暗示const):
例如:
constexpr int len1 = length("abcd") ;
Run Code Online (Sandbox Code Playgroud)
Bjarne Stroustrup总结了我们何时可以确保此isocpp博客条目中的编译时评估,并说:
[...] Herb所说的正确答案是,根据标准,constexpr函数可以在编译器时或运行时进行评估,除非它被用作常量表达式,在这种情况下它必须在编译时进行评估-时间.为了保证编译时评估,我们必须在需要常量表达式的地方使用它(例如,作为数组绑定或作为case标签)或使用它来初始化constexpr.我希望没有自尊的编译器会错过我最初所说的优化机会:"如果constexpr函数的所有参数都是常量表达式,那么它将在编译时进行评估."
因此,这概述了应在编译时对其进行评估的两种情况:
shall be ... converted constant expression
或shall be ... constant expression
使用的任何位置,例如数组绑定.constexpr
如上所述.Ben*_*igt 25
很容易确定对constexpr
函数的调用是导致核心常量表达还是仅仅是优化:
在需要常量表达式的上下文中使用它.
int main()
{
constexpr int test_const = length("abcd");
std::array<char,length("abcdefgh")> test_const2;
}
Run Code Online (Sandbox Code Playgroud)
Max*_*kin 16
请注意,现代编译器(如gcc-4.x)strlen
在编译时为字符串文字做,因为它通常被定义为内部函数.未启用优化.虽然结果不是编译时常量.
例如:
printf("%zu\n", strlen("abc"));
Run Code Online (Sandbox Code Playgroud)
结果是:
movl $3, %esi # strlen("abc")
movl $.LC0, %edi # "%zu\n"
movl $0, %eax
call printf
Run Code Online (Sandbox Code Playgroud)
小智 12
让我提出另一个函数,它在编译时计算字符串的长度而不是递归的.
template< size_t N >
constexpr size_t length( char const (&)[N] )
{
return N-1;
}
Run Code Online (Sandbox Code Playgroud)
无法保证constexpr
在编译时评估函数,但任何合理的编译器都会在启用适当的优化级别时执行此操作.另一方面,必须在编译时评估模板参数.
我使用以下技巧在编译时强制进行评估.不幸的是,它只适用于整数值(即不使用浮点值).
template<typename T, T V>
struct static_eval
{
static constexpr T value = V;
};
Run Code Online (Sandbox Code Playgroud)
现在,如果你写
if (static_eval<int, length("hello, world")>::value > 7) { ... }
Run Code Online (Sandbox Code Playgroud)
您可以确定该if
语句是编译时常量,没有运行时开销.
很简单的:
sizeof("myStringLiteral")
做工作。
内部编译器函数sizeof
在编译时保证进行评估。它是一个强大的编译器功能,但常常被低估。它适用于 C++ 和 C。
注意:您可能需要从 转换size_t
为 int,并减去 1,这两项操作也在编译时完成:
int test_sizeof_text = (int)(sizeof("1234567")-1);
sizeof("text")
是包含终止符 0 的大小,因此 -1 表示字符数。