Consider the following constexpr
function, static_strcmp
, which uses C++17's constexpr
char_traits::compare
function:
#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 shows this gets evaluated at compile-time, and optimised down to:
main: xor eax, eax ret
Remove constexpr
from bool result
:
If we remove the constexpr
from constexpr bool result
, now the call is no longer optimised.
#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 shows we now call into 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
Add a short circuiting length
check:
if we first compare char_traits::length
for the two arguments in static_strcmp
before calling char_traits::compare
, without constexpr
on bool result
, the call is optimised away again.
#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 shows we're back to the call being optimised away:
main: xor eax, eax ret
- Why does removing
constexpr
from the initial call tostatic_strcmp
cause the constant evaluation to fail? - Clearly even without
constexpr
, the call tochar_traits::length
is evaluated at compile time, so why not the same behaviour withoutconstexpr
in the first version ofstatic_strcmp
?
Note, that nothing in the standard explicitly requires
constexpr
function to be called at compile time, see 9.1.5.7 in latest draft:(emphasizes mine)
Now, when the call appears in constant expression, there is no way compiler can avoid running the function at compile time, so it dutifully obliges. When it does not (as in your second snippet) it is just a case of missing optimization. There is no shortage of those around here.