在编译时计算 C 字符串的长度。这真的是一个 constexpr 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25890784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Computing length of a C string at compile time. Is this really a constexpr?
提问by Mircea Ispas
I'm trying to compute the length of a string literal at compile time. To do so I'm using following code:
我正在尝试在编译时计算字符串文字的长度。为此,我使用以下代码:
#include <cstdio>
int constexpr length(const char* str)
{
return *str ? 1 + length(str + 1) : 0;
}
int main()
{
printf("%d %d", length("abcd"), length("abcdefgh"));
}
Everything works as expected, the program prints 4 and 8. The assembly code generated by clang shows that the results are computed at compile time:
一切都按预期工作,程序打印 4 和 8。 clang 生成的汇编代码显示结果是在编译时计算的:
0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"
0x100000f65: movl constexpr int len1 = length("abcd") ;
x4, %esi
0x100000f6a: movl int main()
{
constexpr int test_const = length("abcd");
std::array<char,length("abcdefgh")> test_const2;
}
x8, %edx
0x100000f6f: xorl %eax, %eax
0x100000f71: callq 0x100000f7a ; symbol stub for: printf
My question: is it guaranteed by the standard that length
function will be evaluated compile time?
我的问题:标准是否保证length
将在编译时评估函数?
If this is true the door for compile time string literals computations just opened for me... for example I can compute hashes at compile time and many more...
如果这是真的,那么编译时字符串文字计算的大门就为我打开了……例如,我可以在编译时计算哈希值等等……
采纳答案by Shafik Yaghmour
Constant expressions are not guaranteed to be evaluated at compile time, we only have a non-normative quote from draft C++ standardsection 5.19
Constant expressionsthat says this though:
不能保证在编译时对常量表达式求值,我们只有一个来自C++ 标准草案部分5.19
常量表达式的非规范引用,但它说明了这一点:
[...]>[ Note: Constant expressions can be evaluated during translation.—end note ]
[...]>[ 注意:常量表达式可以在翻译过程中计算。-结束注释]
You can assign the result to constexpr
variable to be sure it is evaluated at compile time, we can see this from Bjarne Stroustrup's C++11 referencewhich says (emphasis mine):
您可以将结果分配给constexpr
变量以确保在编译时对其进行评估,我们可以从Bjarne Stroustrup 的 C++11 参考中看到这一点(强调我的):
In addition to be able to evaluate expressions at compile time, we want to be able to require expressions to be evaluated at compile time; constexpr in front of a variable definition does that(and implies const):
除了能够在编译时计算表达式之外,我们还希望能够要求在编译时计算表达式;变量定义前面的 constexpr 就是这样做的(并暗示 const):
For example:
例如:
printf("%zu\n", strlen("abc"));
Bjarne Stroustrup gives a summary of when we can assure compile time evaluation in this isocpp blog entryand says:
Bjarne Stroustrup 在此isocpp 博客条目中总结了我们何时可以确保编译时评估并说:
[...]The correct answer - as stated by Herb - is that according to the standard a constexpr function may be evaluated at compiler time or run time unless it is used as a constant expression, in which case it must be evaluated at compile-time. To guarantee compile-time evaluation, we must either use it where a constant expression is required (e.g., as an array bound or as a case label) or use it to initialize a constexpr. I would hope that no self-respecting compiler would miss the optimization opportunity to do what I originally said: "A constexpr function is evaluated at compile time if all its arguments are constant expressions."
[...]正确答案 - 如 Herb 所述 - 是根据标准,constexpr 函数可以在编译器时或运行时求值,除非它用作常量表达式,在这种情况下,它必须在编译时求值-时间。为了保证编译时求值,我们必须在需要常量表达式的地方使用它(例如,作为数组绑定或作为 case 标签)或使用它来初始化 constexpr。我希望没有自尊的编译器会错过优化机会来执行我最初所说的:“如果 constexpr 函数的所有参数都是常量表达式,则在编译时对其进行评估。”
So this outlines two cases where it should be evaluated at compile time:
因此,这概述了应在编译时对其进行评估的两种情况:
- Use it where a constant expression is required, this would seem to be anywhere in the draft standard where the phrase
shall be ... converted constant expression
orshall be ... constant expression
is used, such as an array bound. - Use it to initialize a
constexpr
as I outline above.
- 在需要常量表达式的地方使用它,这似乎是标准草案中使用短语
shall be ... converted constant expression
or 的任何地方shall be ... constant expression
,例如数组绑定。 - 使用它来初始化 a,
constexpr
正如我上面概述的那样。
回答by Ben Voigt
It's really easy to find out whether a call to a constexpr
function results in a core constant expressionor is merely being optimized:
很容易找出对constexpr
函数的调用是导致核心常量表达式还是仅仅被优化:
Use it in a context where a constant expression is required.
在需要常量表达式的上下文中使用它。
movl , %esi # strlen("abc")
movl $.LC0, %edi # "%zu\n"
movl template< size_t N >
constexpr size_t length( char const (&)[N] )
{
return N-1;
}
, %eax
call printf
回答by Maxim Egorushkin
Just a note, that modern compilers (like gcc-4.x) do strlen
for string literals at compile time because it is normally defined as an intrinsic function. With no optimizations enabled. Although the result is not a compile time constant.
请注意,现代编译器(如 gcc-4.x)strlen
在编译时会处理字符串文字,因为它通常被定义为内部函数。没有启用优化。虽然结果不是编译时常量。
E.g.:
例如:
template<typename T, T V>
struct static_eval
{
static constexpr T value = V;
};
Results in:
结果是:
if (static_eval<int, length("hello, world")>::value > 7) { ... }
回答by user2436830
Let me propose another function that computes the length of a string at compile time without being recursive.
让我提出另一个函数,它在编译时计算字符串的长度而不是递归的。
##代码##Have a look at this sample code at ideone.
在 ideone 上查看此示例代码。
回答by 5gon12eder
There is no guarantee that a constexpr
function is evaluated at compile-time, though any reasonable compiler will do it at appropriate optimization levels enabled. On the other hand, template parameters mustbe evaluated at compile-time.
constexpr
尽管任何合理的编译器都会在启用的适当优化级别上执行此操作,但不能保证在编译时评估函数。另一方面,必须在编译时评估模板参数。
I used the following trick to force evaluation at compile time. Unfortunately it only works with integral values (ie not with floating point values).
我使用以下技巧在编译时强制评估。不幸的是,它只适用于整数值(即不适用于浮点值)。
##代码##Now, if you write
现在,如果你写
##代码##you can be sure that the if
statement is a compile-time constant with no run-time overhead.
您可以确定该if
语句是一个没有运行时开销的编译时常量。
回答by kaedinger
A short explanation from Wikipedia's entry on Generalized constant expressions:
维基百科关于广义常量表达式的条目的简短解释:
The use of constexpr on a function imposes some limitations on what that function can do. First, the function must have a non-void return type. Second, the function body cannot declare variables or define new types. Third, the body may contain only declarations, null statements and a single return statement. There must exist argument values such that, after argument substitution, the expression in the return statement produces a constant expression.
在函数上使用 constexpr 对该函数的功能施加了一些限制。首先,该函数必须具有非 void 返回类型。其次,函数体不能声明变量或定义新类型。第三,主体可能只包含声明、空语句和单个返回语句。必须存在参数值,以便在参数替换后,return 语句中的表达式生成一个常量表达式。
Having the constexpr
keyword before a function definition instructs the compiler to check if these limitations are met. If yes, and the function is called with a constant, the returned value is guaranteed to be constant and thus can be used anywhere a constant expression is required.
在constexpr
函数定义之前使用关键字指示编译器检查是否满足这些限制。如果是,并且使用常量调用函数,则返回值保证是常量,因此可以在需要常量表达式的任何地方使用。