【发布时间】:2019-03-20 14:57:44
【问题描述】:
考虑下面的constexpr函数static_strcmp,它使用了C++17的constexprchar_traits::compare函数:
#include <string>
constexpr bool static_strcmp(char const *a, char const *b)
{
return std::char_traits<char>::compare(a, b,
std::char_traits<char>::length(a)) == 0;
}
int main()
{
constexpr const char *a = "abcdefghijklmnopqrstuvwxyz";
constexpr const char *b = "abc";
constexpr bool result = static_strcmp(a, b);
return result;
}
godbolt 表明这是在编译时评估的,并优化为:
main: xor eax, eax ret
从bool result 中删除constexpr:
如果我们从constexpr bool result 中删除constexpr,现在调用将不再优化。
#include <string>
constexpr bool static_strcmp(char const *a, char const *b)
{
return std::char_traits<char>::compare(a, b,
std::char_traits<char>::length(a)) == 0;
}
int main()
{
constexpr const char *a = "abcdefghijklmnopqrstuvwxyz";
constexpr const char *b = "abc";
bool result = static_strcmp(a, b); // <-- note no constexpr
return result;
}
godbolt 表示我们现在调用memcmp:
.LC0: .string "abc" .LC1: .string "abcdefghijklmnopqrstuvwxyz" main: sub rsp, 8 mov edx, 26 mov esi, OFFSET FLAT:.LC0 mov edi, OFFSET FLAT:.LC1 call memcmp test eax, eax sete al add rsp, 8 movzx eax, al ret
添加短路length检查:
如果我们首先比较char_traits::length 中static_strcmp 中的两个参数之前 调用char_traits::compare,没有 constexpr 上bool result,调用是再次优化。
#include <string>
constexpr bool static_strcmp(char const *a, char const *b)
{
return
std::char_traits<char>::length(a) == std::char_traits<char>::length(b)
&& std::char_traits<char>::compare(a, b,
std::char_traits<char>::length(a)) == 0;
}
int main()
{
constexpr const char *a = "abcdefghijklmnopqrstuvwxyz";
constexpr const char *b = "abc";
bool result = static_strcmp(a, b); // <-- note still no constexpr!
return result;
}
godbolt 表明我们又回到了正在优化的呼叫:
main: xor eax, eax ret
- 为什么从对
static_strcmp的初始调用中删除constexpr会导致持续评估失败? - 显然,即使没有
constexpr,对char_traits::length的调用也是在编译时评估的,那么为什么在static_strcmp的第一个版本中没有constexpr的行为不一样呢?李>
【问题讨论】:
-
第二个片段是否访问了
b指针越界,所以它是未定义的行为?它是,looks like 和 looks like 这是一个普通的 memcmp。所以这是未定义的行为。 -
第一种情况和做任何其他函数调用的问题一样,编译器不必优化它。
-
但是
char_traits<char>::compare中的__constant_char_array_p(__s2, __n)将评估为假,因为b[4]不是一个常量表达式。所以它可能是也可能不是 constexpr,因为它是未定义的。compare函数不是strcmp它是memcmp,它不会在空终止字符处停止。 -
因为 constexpr 函数不能保证在编译时被调用,除非它们的结果在需要常量表达式的上下文中使用。不仅仅是缺少优化的情况,还有数以百万计的情况。
-
我觉得这是相关的,如果不是重复的stackoverflow.com/questions/54181797/…
标签: c++ c++17 constexpr char-traits