On 07/17/2017 11:15 AM,
dime...@gmail.com wrote:
> □ Motivation
> In C++, the same semantic functions sometimes have to write two
> different versions, a constexpr version, an efficient general version.
> For example:
> constexpr auto StrLen(const char *s) {auto tp=s;while(*s) s++;return s-tp;}
> auto StrLenSSE4(const char *s){...}
> □ Proposal
> Gcc has a built-in function __builtin_constant_p (v) to determine
> whether a value is a compile time constant, but it can only be used for
> macros, and v can only be one literal.
> Can you provide a function of *is_constexpr*(v) to determine whether v
> is a compile time constant?
> In this way, the function above can use a unified interface.
> constexpr auto StrLen(const char *s){
> if constexpr(*is_constexpr*(s)) {
> auto tp=s;while(*s) s++;return s-tp;
> }
> else return StrLenSSE4(s);
> }
Note that GCC's __builtin_constant_p _can_ be used for the
above. It's how C++17 constexpr char_traits<>::length() etc.
is currently implemented in libstdc++ trunk. (BTW, you can
just use char_traits<>::length() in this case.)
#include <string.h>
static constexpr bool
constant_string_p(const char* s)
{
while (__builtin_constant_p(*s) && *s)
s++;
return __builtin_constant_p(*s);
}
static constexpr size_t constexpr_strlen(const char* s)
{
auto tp = s;
while (*s)
s++;
return s - tp;
}
constexpr size_t my_strlen(const char* s) noexcept
{
if (constant_string_p(s))
return constexpr_strlen(s);
return strlen(s);
}
static_assert (my_strlen ("") == 0);
static_assert (my_strlen ("hello") == 5);
static_assert (my_strlen ("he\0llo") == 2);
static const char array[] = "foo";
static_assert (my_strlen (array) == 3);
constexpr bool check()
{
char s[] = "str";
s[0] = 'l';
s[1] = '\0';
return my_strlen(s) == 1;
}
static_assert(check());
int main (int argc, char** argv)
{
return my_strlen(argv[0]);
}
$ g++ constexpr_strlen.cc -o constexpr_strlen -g3 -O2 -std=gnu++17
$ gdb --batch -q ./constexpr_strlen -ex "disassemble main"
Dump of assembler code for function main(int, char**):
0x00000000004004c0 <+0>: sub $0x8,%rsp
0x00000000004004c4 <+4>: mov (%rsi),%rdi
0x00000000004004c7 <+7>: callq 0x400490 <strlen@plt>
0x00000000004004cc <+12>: add $0x8,%rsp
0x00000000004004d0 <+16>: retq
End of assembler dump.
$