Constexpr can be awsome and useful for compilation optimisation. For example...
strlen(char*)
Can be precompiled using....
constexpr inline size_t strlen_constexpr(char* baseChar) {
return (
( baseChar[0] == 0 )
?(// if {
0
)// }
:(// else {
strlen_constexpr( baseChar+1 ) + 1
)// }
);
}
Which gives it a runtime cost of "0" when optimised... But is more than 10+x slower on runtime
// Test results ran on a 2010 macbook air
--------- strlen ---------
Time took for 100,000 runs:1054us.
Avg Time took for 1 run: 0.01054us.
--------- strlen_constexpr ---------
Time took for 100,000 runs:19098us.
Avg Time took for 1 run: 0.19098us.
Are there any existing macro / template hack where a single unified function can be used instead. ie.
constexpr size_t strlen_smart(char* baseChar) {
#if constexpr
... constexpr function
#else its runtime
... runtime function
}
Or some overloading hack that would allow the following
constexpr size_t strlen_smart(char* baseChar) {
... constexpr function
}
inline size_t strlen_smart(char* baseChar) {
... runtime function
}
Note: This question applies to the concept in general. Of having 2 separate functions for runtime and constexpr instead of the example functions given.
Disclaimer: Setting the compiler to -O3 (optimization level) is more than enough to fix 99.9% of static char optimizations making all the examples above "pointless". But that's beside the point of this question, as it applies to other "examples", and not just strlen.
I don't know any generic way, but I know two specific cases where it is possible.
Specific case of some compilers
Also gcc, and clang which copies all features of gcc, have a built-in function __builtin_constant_p. I am not sure whether gcc will correctly see argument to inline function as constant, but I fear you'd have to use it from a macro:
#define strlen_smart(s) \
(__builtin_constant_p(s) && __builtin_constant_p(*s) ? \
strlen_constexpr(s) : \
strlen(s))
Might be of use. Note that I am testing both s and *s for constexpr, because pointer to static buffer is a compile time constant while it's length is not.
Bonus: Specific case of literals (not an actual answer)
For the specific cast of strlen you can use the fact that string literals are not of type const char * but of type const char[N] that implicitly converts to const char *. But it also converts to const char (&)[N] as well while const char * does not.
So you can define:
template <size_t N>
constexpr size_t strlen_smart(const char (&array)[N])
(plus obviously strlen_smart on const char * forwards to strlen)
I've sometimes used function with this type of argument even in C++98 with definition corresponding to (I didn't try to overload strlen itself, but the overloads were so I could avoid calling it):
template <size_t N>
size_t strlen_smart(const char (&)[N]) { return N - 1; }
This has the problem that for
char buffer[10] = { 0 };
strlen_smart(buffer);
should say 0, but that optimized variant just says 9. The functions don't make sense to be called on buffers like that so I didn't care.
Related
I'm writing a hashing function to help speed up string comparisons.
My codebase compares strings against a lot of const char[] constants, and it would be ideal if I could work with hashes instead. I went ahead and translated xxHash to modern C++, and I have a working prototype that does work at compile time, but I'm not sure what the function definition should be for the main hashing function.
At the moment, I have this:
template <size_t arr_size>
constexpr uint64_t xxHash64(const char(data)[arr_size])
{...}
This does work, and I am able to do a compile time call like this
constexpr char myString[] = "foobar";
constexpr uint64_t hashedString = xxHash64<sizeof myString>(myString);
[Find a minimal example here]
All good so far, but I would like to add a user-defined literal wrapper function for some eye candy, and this is where the problem lies.
UDLs come with a fixed prototype, as specified here
The Microsoft doc stipulates "Also, any of these operators can be defined as constexpr".
But when I try to call my hashing function from a constexpr UDL:
constexpr uint64_t operator "" _hashed(const char *arr, size_t size) {
return xxHash64<size>(arr);
}
function "xxHash64" cannot be called with the given argument list
argument types are: (const char*)
And the error does make sense. My function expects a character array, and instead it gets a pointer.
But if I were to modify the definition of my xxHash64 function to take a const char *, I can no longer work in a constexpr context because the compiler needs to resolve the pointer first, which happens at runtime.
So am I doing anything wrong here, or is this a limitation of UDLs or constexpr functions as a whole?
Again, I'm not 100% sure the templated definition at the top is the way to go, but I'm not sure how else I could read characters from a string at compile time.
I'm not limited by any compiler version or library. If there is a better way to do this, feel free to suggest.
there is no problem to call constexpr function with constexpr pointer as constant expression
constexpr uint64_t xxHash64(const char* s){return s[0];}
constexpr uint64_t operator "" _g(const char *arr,std::size_t){
return xxHash64(arr);
}
int main()
{
xxHash64("foo");
constexpr auto c = "foobar"_g;
return c;
}
would just work fine.
with c++20, you can also get the size as constant expression with string literal operator template.
#include <cstdint>
template <std::size_t arr_size>
constexpr std::uint64_t xxHash64(const char(&data)[arr_size]){
return data[0];
}
// template <std::size_t N> // can also be full class template (with CTAD)
struct hash_value{
std::uint64_t value;
template <std::size_t N>
constexpr hash_value(const char(&p)[N]):value(xxHash64(p)){}
};
template < hash_value v >
constexpr std::uint64_t operator ""_hashed() { return v.value; }
int main()
{
constexpr auto v = "foobar"_hashed;
return v;
}
Suppose I have a function that takes a string as input:
SomeOutputType f_impl(const char* s);
Most call sites just use string literals as input, e.g. f("Hello, world"). Suppose I have implemented the following function to compute the result at compile time
template <char...> SomeOutputType f_impl();
My question is, is there a way to let the call sites like f("Hello, world") calls the templated form, while for general call sites like string s="Hello, world"; f(s.c_str()); calls the general form? For clarification, auto s = "Hello, world"; f(s); don't have to call the templated form because s is now a variable and no longer a compile time constant.
A useful case for this question is to optimize printf. In most cases the format will be string literals so a lot of things can be done at compile time to optimize things, instead of parsing the format at runtime.
No, a string literal like "foo" has the type const char[S + 1] where S is the number of characters you wrote. It behaves like an array of that type with no special rules.
In C++03, there was a special rule that said that a string literal could convert to char*. That allowed you to say
#define isStringLiteral(X) \
isConvertibleToCharStar(X) && hasTypeConstCharArray(X)
For example isStringLiteral(+"foo") would yield false, and isStringLiteral("foo") would yield true. Even this possibiliy would not have allowed you to call a function with a string literal argument and behave differently.
C++11 removed that special conversion rule and string literals behave like any other arrays. In C++11 as a dirty hack you can compose some macros, matching some simple string literals without handling escape sequences
constexpr bool isStringLiteral(const char *x, int n = 0) {
return *x == '"' ?
n == 0 ?
isStringLiteral(x + 1, n + 1)
: !*(x + 1)
: (*x && n != 0 && isStringLiteral(x + 1, n + 1));
}
#define FastFun(X) \
(isStringLiteral(#X) ? fConstExpr(X, sizeof(X) - 1) : f(X))
While I haven't tested this, I think if you just declare the function constexpr and compile with high optimization, the compiler will compute at compile time whenever possible. As a bonus, you don't need to write the code twice. On the other hand, you have to write it once in constexpr style.
If I understand the question correctly, I actually think something like this is possible using a function overload. Here's an article that shows the basic idea. In your case I think it would be sufficient to have the following two overloads:
void f(char const *);
template<unsigned int N>
void f(char const (&)[N]);
The latter should be invoked when the string is a string literal, the latter at other times. If the compiler is sufficiently good at optimizing then calls to the latter may be evaluated at compile time.
EDIT:
Alright, it bothered me that the above solution didn't work, so I did some playing around and I think I came up with a solution:
#include <string>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct is_string_literal {
enum { value = false };
};
template<unsigned int N>
struct is_string_literal<char const (&)[N]> {
enum { value = true };
};
template<typename T>
typename boost::disable_if<is_string_literal<T> >::type
foo(T) {
std::cout << "foo1" << std::endl;
}
template<int N>
void foo(char const (&)[N]) {
std::cout << "foo2" << std::endl;
}
int main( ) {
std::string bar = "blah";
char const str[] = "blah";
foo(str);
foo("blah");
foo(bar.data());
}
The output (on GCC 4.4 with -O3) is:
foo2
foo2
foo1
I admit that I don't completely understand why this works when the previous solution didn't. Maybe there's something about overload resolution that I don't completely understand.
I'm trying to create a compile-time bit mask using metaprograming techniques, my idea is to create something like this:
unsigned int Mask3 = Mask<2>(); // value = 0x03 = b00000000000000000000000000000011
unsigned int Mask3 = Mask<3>(); // value = 0x07 = b00000000000000000000000000000111
unsigned int Mask3 = Mask<7>(); // value = 0x7F = b00000000000000000000000001111111
The code that I'm trying is this:
template <const unsigned int N> const unsigned int Mask()
{
if (N <= 1)
{
return 1;
}
else
{
return ((1 << N) | Mask<N - 1>());
}
}
return 1;
But it result in tons pairs of warnings:
warning C4554: '<<' : check operator precedence for possible error
warning C4293: '<<' : shift count negative or too big
And in the end, the compile error:
error C1202: recursive type or function dependency context too complex.
So, I deduce that the recursivity never ends and falls into a compiler infinite loop but I'm don't understanding WHY.
As has already been pointed out, you're depending on a runtime check to
stop a compile time recursion, which can't work. More importantly,
perhaps, for what you want to do, is that you're defining a function,
which has no value until you call it. So even after you stop the
recursion with a specialization, you still have a nested sequence of
functions, which will be called at runtime.
If you want full compile time evaluation, you must define a static data
member of a class template, since that's the only way a compile time
constant can appear in a template. Something like:
template <unsigned int N>
struct Mask
{
static unsigned int const value = (1 << (N - 1)) | Mask<N - 1>::value;
};
template <>
struct Mask<0>
{
static unsigned int const value = 0;
};
(I've also corrected the numerical values you got wrong.)
Of course, you don't need anything this complicated. The following
should do the trick:
template <unsigned int N>
struct Mask
{
static unsigned int const value = (1 << (N + 1)) - 1;
};
template <>
struct Mask<0>
{
static unsigned int const value = 0;
};
(You still need the specialization for 0. Otherwise, 0 means all bits
set.)
Finally, of course: to access the value, you need to write something
like Mask<3>::value. (You might want to wrap this in a macro.)
It doesn't need to be recursive. This should work just fine :
template <const unsigned int N> const unsigned int Mask()
{
return ((1 << N) - 1);
}
It doesn't even need to be a template really. An (inlined) function is ok.
Note that if you want to support any value of N, specifically N >= sizeof(unsigned int) * CHAR_BIT, you probably want to treat those as a special case.
A template is created at compile time, but you are relying on run time behavior to stop the recursion.
For example, if you instantiate Mask<2>, it is going to use Mask<1>, which is going to use Mask<0>, which is going to use Mask<-1>, etc.
You have a runtime check for N being <= 1, but this doesn't help when it's compiling. It still creates an infinite sequence of functions.
To blunt template instantiation recursion you need to introduce one explicit specialization:
template <0> const unsigned int Mask()
{
return 1;
}
Your recursion never ends, because compiler tries to generate template implementation for both if-branches. So, when it generates Mask<0> it also generates Mask<0xffffffff> and so on
C++11 -- no recursion or templates:
constexpr unsigned mask(unsigned N) { return unsigned(~(-1<<N)); }
So far the answers only addressed the second error (C1202), but you asked more than that.
Warning C4554 is caused by a Microsoft compiler bug involving template parameters and the << operator. So, (1 << N) generates a warning. If N were an ordinary parameter, there would be no warning of course.
The very simple workaround is to use (1 << (N)) instead of (1 << N), and C4554 goes away!
This is just something that has bothered me for the last couple of days, I don't think it's possible to solve but I've seen template magic before.
Here goes:
To get the number of elements in a standard C++ array I could use either a macro (1), or a typesafe inline function (2):
(1)
#define sizeof_array(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
(2)
template <typename T>
size_t sizeof_array(const T& ARRAY){
return (sizeof(ARRAY)/sizeof(ARRAY[0]));
}
As you can see, the first one has the problem of being a macro (for the moment I consider that a problem) and the other one has the problem of not being able to get the size of an array at compile time; ie I can't write:
enum ENUM{N=sizeof_array(ARRAY)};
or
BOOST_STATIC_ASSERT(sizeof_array(ARRAY)==10);// Assuming the size 10..
Does anyone know if this can be solved?
Update:
This question was created before constexpr was introduced. Nowadays you can simply use:
template <typename T>
constexpr auto sizeof_array(const T& iarray) {
return (sizeof(iarray) / sizeof(iarray[0]));
}
Try the following from here:
template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&array)[N] ))[N];
#define mycountof( array ) (sizeof( _ArraySizeHelper( array ) ))
int testarray[10];
enum { testsize = mycountof(testarray) };
void test() {
printf("The array count is: %d\n", testsize);
}
It should print out: "The array count is: 10"
In C++1x constexpr will get you that:
template <typename T, size_t N>
constexpr size_t countof(T(&)[N])
{
return N;
}
The best I can think of is this:
template <class T, std::size_t N>
char (&sizeof_array(T (&a)[N]))[N];
// As litb noted in comments, you need this overload to handle array rvalues
// correctly (e.g. when array is a member of a struct returned from function),
// since they won't bind to non-const reference in the overload above.
template <class T, std::size_t N>
char (&sizeof_array(const T (&a)[N]))[N];
which has to be used with another sizeof:
int main()
{
int a[10];
int n = sizeof(sizeof_array(a));
std::cout << n << std::endl;
}
[EDIT]
Come to think of it, I believe this is provably impossible to do in a single "function-like call" in C++03, apart from macros, and here's why.
On one hand, you will clearly need template parameter deduction to obtain size of array (either directly, or via sizeof as you do). However, template parameter deduction is only applicable to functions, and not to classes; i.e. you can have a template parameter R of type reference-to-array-of-N, where N is another template parameter, but you'll have to provide both R and N at the point of the call; if you want to deduce N from R, only a function call can do that.
On the other hand, the only way any expression involving a function call can be constant is when it's inside sizeof. Anything else (e.g. accessing a static or enum member on return value of function) still requires the function call to occur, which obviously means this won't be a constant expression.
It's not exactly what you're looking for, but it's close - a snippet from winnt.h which includes some explanation of what the #$%^ it's doing:
//
// RtlpNumberOf is a function that takes a reference to an array of N Ts.
//
// typedef T array_of_T[N];
// typedef array_of_T &reference_to_array_of_T;
//
// RtlpNumberOf returns a pointer to an array of N chars.
// We could return a reference instead of a pointer but older compilers do not accept that.
//
// typedef char array_of_char[N];
// typedef array_of_char *pointer_to_array_of_char;
//
// sizeof(array_of_char) == N
// sizeof(*pointer_to_array_of_char) == N
//
// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T);
//
// We never even call RtlpNumberOf, we just take the size of dereferencing its return type.
// We do not even implement RtlpNumberOf, we just decare it.
//
// Attempts to pass pointers instead of arrays to this macro result in compile time errors.
// That is the point.
//
extern "C++" // templates cannot be declared to have 'C' linkage
template <typename T, size_t N>
char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N];
#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A)))
The RTL_NUMBER_OF_V2() macro ends up being used in the more readable ARRAYSIZE() macro.
Matthew Wilson's "Imperfect C++" book also has a discussion of the techniques that are used here.
The Problem
I like Adisak's answer:
template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&arr)[N] ))[N];
#define COUNTOF( arr ) (sizeof( _ArraySizeHelper( arr ) ))
It's what Microsoft uses for the _countof macro in VS2008, and it's got some nice features:
It operates at compile time
It's typesafe (i.e. it will generate a compile-time error if you give it a pointer, which arrays degrade too all too easily)
But as pointed out by Georg, this approach uses templates, so it's not guaranteed to work with local types for C++03:
void i_am_a_banana() {
struct { int i; } arr[10];
std::cout << COUNTOF(arr) << std::endl; // forbidden in C++03
}
Fortunately, we're not out luck.
The Solution
Ivan Johnson came up with a clever approach that wins on all accounts: it's typesafe, compile-time, and works with local types:
#define COUNTOF(arr) ( \
0 * sizeof(reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(arr)) + \
0 * sizeof(::Bad_arg_to_COUNTOF::check_type((arr), &(arr))) + \
sizeof(arr) / sizeof((arr)[0]) )
struct Bad_arg_to_COUNTOF {
class Is_pointer; // incomplete
class Is_array {};
template <typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
For those who are interested, it works by inserting two "tests" before the standard sizeof-based array-size macro. Those tests don't impact the final calculation, but are designed to generate compile errors for non-array types:
The first test fails unless arr is integral, enum, pointer, or array. reinterpret_cast<const T*> should fail for any other types.
The second test fails for integral, enum, or pointer types.
Integral and enum types will fail because there's no version of check_type that they match, since check_type expects pointers.
Pointer types will fail because they'll match the templated version of check_type, but the return type (Is_pointer) for the templated check_type is incomplete, which will produce an error.
Array types will pass because taking the address of an array of type T
will give you T (*)[], aka a pointer-to-an-array, not a pointer-to-a-pointer. That means that the templated version of check_type won't match. Thanks to SFINAE, the compiler will move on to the non-templated version of check_type, which should accept any pair of pointers. Since the return type for the non-templated version is defined completely, no error will be produced. And since we're not dealing with templates now, local types work fine.
If you are on a Microsoft only platform, you can take advantage of the _countof macro. This is a non-standard extension which will return the count of elements within an array. It's advantage over most countof style macros is that it will cause a compilation error if it's used on a non-array type.
The following works just fine (VS 2008 RTM)
static int ARRAY[5];
enum ENUM{N=_countof(ARRAY)};
But once again, it's MS specific so this may not work for you.
You can't solve it in general, thats one the reasons for array wrappers like boost array (plus stl-style behaviour of course).
It appears not to be possible to obtain the sizeof array as a compile-time constant without a macro with current C++ standard (you need a function to deduce the array size, but function calls are not allowed where you need a compile-time constant). [Edit: But see Minaev's brilliant solution!]
However, your template version isn't typesafe either and suffers from the same problem as the macro: it also accepts pointers and notably arrays decayed to a pointer. When it accepts a pointer, the result of sizeof(T*) / sizeof(T) cannot be meaningful.
Better:
template <typename T, size_t N>
size_t sizeof_array(T (&)[N]){
return N;
}
Without C++0x, the closest I can get is:
#include <iostream>
template <typename T>
struct count_of_type
{
};
template <typename T, unsigned N>
struct count_of_type<T[N]>
{
enum { value = N };
};
template <typename T, unsigned N>
unsigned count_of ( const T (&) [N] )
{
return N;
};
int main ()
{
std::cout << count_of_type<int[20]>::value << std::endl;
std::cout << count_of_type<char[42]>::value << std::endl;
// std::cout << count_of_type<char*>::value << std::endl; // compile error
int foo[1234];
std::cout << count_of(foo) << std::endl;
const char* bar = "wibble";
// std::cout << count_of( bar ) << std::endl; // compile error
enum E1 { N = count_of_type<int[1234]>::value } ;
return 0;
}
which either gives you a function you can pass the variable to, or a template you can pass the type too. You can't use the function for a compile time constant, but most cases you know the type, even if only as template parameter.
Now STL libraries are available to decide/select array size compile time
#include <iostream>
#include <array>
template<class T>
void test(T t)
{
int a[std::tuple_size<T>::value]; // can be used at compile time
std::cout << std::tuple_size<T>::value << '\n';
}
int main()
{
std::array<float, 3> arr;
test(arr);
}
Output:
3
Sometimes it is necessary to compare a string's length with a constant.
For example:
if ( line.length() > 2 )
{
// Do something...
}
But I am trying to avoid using "magic" constants in code.
Usually I use such code:
if ( line.length() > strlen("[]") )
{
// Do something...
}
It is more readable, but not efficient because of the function call.
I wrote template functions as follow:
template<size_t N>
size_t _lenof(const char (&)[N])
{
return N - 1;
}
template<size_t N>
size_t _lenof(const wchar_t (&)[N])
{
return N - 1;
}
// Using:
if ( line.length() > _lenof("[]") )
{
// Do something...
}
In a release build (VisualStudio 2008) it produces pretty good code:
cmp dword ptr [esp+27Ch],2
jbe 011D7FA5
And the good thing is that the compiler doesn't include the "[]" string in the binary output.
Is it a compiler specific optimisation or is it a common behavior?
Why not
sizeof "[]" - 1;
(minus one for the trailing null. You could
do sizeof "[]" - sizeof '\0', but sizeof '\0'
is often sizeof( int ) in C, and "- 1 " is
perfectly readable.)
The capability to inline a function call is both a compiler-specific optimization and a common behavior. That is, many compilers can do it, but they aren't required to.
I think most compilers will optimize it away when optimizations are enabled. If they're disabled, it might slow your program down much more than necessary.
I would prefer your template functions, as they're guaranteed to not call strlen at runtime.
Of course, rather than writing separate functions for char and wchar_t, you could add another template argument, and get a function which works for any type:
template <typename Char_t, int len>
int static_strlen(const Char_t (&)[N] array){
return len / sizeof(Char_t) - 1;
}
(As already mentioned in comments, this will give funny results if passed an array of ints, but are you likely to do that? It's meant for strings, after all)
A final note, the name _strlen is bad. All name at namespace scope beginning with an underscore are reserved to the implementation. You risk some nasty naming conflicts.
By the way, why is "[]" less of a magic constant than 2 is?
In both cases, it is a literal that has to be changed if the format of the string it is compared to changes.
#define TWO 2
#define STRING_LENGTH 2
/* ... etc ... */
Seriously, why go through all this hassle just to avoid typing a 2? I honestly think you're making your code less readable, and other programmers are going to stare at you like you're snorting the used coffee from the filter.