Converting macros sequence to templated one - c++

I have following sequence of functions with marcos to setup hook in detours.
SETUP_ORIG_FUNC(string_copy_n);
char* __cdecl HOOK(string_copy_n)(char* dst, const char* src, size_t size)
{
if (src && dst && size && !convert_ulong_lock && Config::Setting::enable_translation) {
auto tstr = Dictionary::GetSingleton()->Get(src);
if (tstr) {
return ORIGINAL(string_copy_n)(dst, tstr.value().c_str(), tstr.value().size());
}
}
return ORIGINAL(string_copy_n)(dst, src, size);
}
Marcoses and typedef:
#define SETUP_ORIG_FUNC(fn_name) fn_name fn_name##_orig = (fn_name)(module_handle + Config::Offset::fn_name);
#define HOOK(fn_name) fn_name##_hook
#define ORIGINAL(fn_name) fn_name##_orig
typedef char*(__cdecl* string_copy_n)(char* dst, const char* src, size_t size);
Config::Offset::string_copy_n stores offset of specific function
How can I implement all this with templates? Myabe there is more efficient and compact way?
I tried different templates with Ret and ...Args or just typedef as input, but always had invalid code. This is my best try:
template <uintptr_t offset, typename Ret, typename ...Args>
Ret Original(Args&&... args) {
return (Ret)(module_handle + offset)(args...);
}

Related

C++ compile-time substring

I have very big code-base, which uses __FILE__ extensively for logging. However, it includes full path, which is (1) not needed, (2) might case security violations.
I'm trying to write compile-time sub-string expression. Ended up with this solution
static constexpr cstr PastLastSlash(cstr str, cstr last_slash)
{
return *str == '\0' ? last_slash : *str == '/' ? PastLastSlash(str + 1, str + 1) : PastLastSlash(str + 1, last_slash);
}
static constexpr cstr PastLastSlash(cstr str)
{
return PastLastSlash(str, str);
}
// usage
PastLastSlash(__FILE__);
This works good, I've checked assembly code, line is trimmed in compile time, only file name is present in binary.
However, this notation is too verbose. I would like to use macro for this, but failed. Proposed example from the link above
#define __SHORT_FILE__ ({constexpr cstr sf__ {past_last_slash(__FILE__)}; sf__;})
doesn't work for MSVC compiler (I'm using MSVC 2017). Is there any other method do to so using c++17?
UPD1: clang trimmed by function https://godbolt.org/z/tAU4j7
UPD2: looks like it's possible to do trim on compile time using functions, but full string is swill be present in binary.
The idea is to create truncated array of characters, but it needs to use only compile time features. Generating data array through variadic template with pack of char forces compiler to generate data without direct relation to passed string literal. This way compiler cannot use input string literal, especially when this string is long.
Godbolt with clang: https://godbolt.org/z/WdKNjB.
Godbolt with msvc: https://godbolt.org/z/auMEIH.
The only problem is with template depth compiler settings.
First we define int variadic template to store sequence of indexes:
template <int... I>
struct Seq {};
Pushing int to Seq:
template <int V, typename T>
struct Push;
template <int V, int... I>
struct Push<V, Seq<I...>>
{
using type = Seq<V, I...>;
};
Creating sequence:
template <int From, int To>
struct MakeSeqImpl;
template <int To>
struct MakeSeqImpl<To, To>
{
using type = Seq<To>;
};
template <int From, int To>
using MakeSeq = typename MakeSeqImpl<From, To>::type;
template <int From, int To>
struct MakeSeqImpl : Push<From, MakeSeq<From + 1, To>> {};
Now we can make sequence of compile time ints, meaning that MakeSeq<3,7> == Seq<3,4,5,6,7>. Still we need something to store selected characters in array, but using compile time representation, which is variadic template parameter with characters:
template<char... CHARS>
struct Chars {
static constexpr const char value[] = {CHARS...};
};
template<char... CHARS>
constexpr const char Chars<CHARS...>::value[];
Next we something to extract selected characters into Chars type:
template<typename WRAPPER, typename IDXS>
struct LiteralToVariadicCharsImpl;
template<typename WRAPPER, int... IDXS>
struct LiteralToVariadicCharsImpl<WRAPPER, Seq<IDXS...> > {
using type = Chars<WRAPPER::get()[IDXS]...>;
};
template<typename WRAPPER, typename SEQ>
struct LiteralToVariadicChars {
using type = typename LiteralToVariadicCharsImpl<WRAPPER, SEQ> :: type;
};
WRAPPER is a type that contain our string literal.
Almost done. The missing part is to find last slash. We can use modified version of the code found in the question, but this time it returns offset instead of pointer:
static constexpr int PastLastOffset(int last_offset, int cur, const char * const str)
{
if (*str == '\0') return last_offset;
if (*str == '/') return PastLastOffset(cur + 1, cur + 1, str + 1);
return PastLastOffset(last_offset, cur + 1, str + 1);
}
Last util to get string size:
constexpr int StrLen(const char * str) {
if (*str == '\0') return 0;
return StrLen(str + 1) + 1;
}
Combining everything together using define:
#define COMPILE_TIME_PAST_LAST_SLASH(STR) \
[](){ \
struct Wrapper { \
constexpr static const char * get() { return STR; } \
}; \
using Seq = MakeSeq<PastLastOffset(0, 0, Wrapper::get()), StrLen(Wrapper::get())>; \
return LiteralToVariadicChars<Wrapper, Seq>::type::value; \
}()
Lambda function is to have nice, value-like feeling when using this macro. It also creates a scope for defining Wrapper structure. Generating this structure with inserted string literal using macro, leads to situation when the string literal is bounded to type.
Honestly I would not use this kind of code in production. It is killing compilers.
Both, in case of security reasons and memory usage, I would recommend using docker with custom, short paths for building.
You can using std::string_view:
constexpr auto filename(std::string_view path)
{
return path.substr(path.find_last_of('/') + 1);
}
Usage:
static_assert(filename("/home/user/src/project/src/file.cpp") == "file.cpp");
static_assert(filename("./file.cpp") == "file.cpp");
static_assert(filename("file.cpp") == "file.cpp");
See it compile (godbolt.org).
For Windows:
constexpr auto filename(std::wstring_view path)
{
return path.substr(path.find_last_of(L'\\') + 1);
}
With C++17, you can do the following (https://godbolt.org/z/68PKcsPzs):
#include <cstdio>
#include <array>
namespace details {
template <const char *S, size_t Start = 0, char... C>
struct PastLastSlash {
constexpr auto operator()() {
if constexpr (S[Start] == '\0') {
return std::array{C..., '\0'};
} else if constexpr (S[Start] == '/') {
return PastLastSlash<S, Start + 1>()();
} else {
return PastLastSlash<S, Start + 1, C..., (S)[Start]>()();
}
}
};
}
template <const char *S>
struct PastLastSlash {
static constexpr auto a = details::PastLastSlash<S>()();
static constexpr const char * value{a.data()};
};
int main() {
static constexpr char f[] = __FILE__;
puts(PastLastSlash<f>::value);
return 0;
}
With C++14, it's a bit more complicated because of the more limited constexpr (https://godbolt.org/z/bzGec5GMv):
#include <cstdio>
#include <array>
namespace details {
// Generic form: just add the character to the list
template <const char *S, char ch, size_t Start, char... C>
struct PastLastSlash {
constexpr auto operator()() {
return PastLastSlash<S, S[Start], Start + 1, C..., ch>()();
}
};
// Found a '/', reset the character list
template <const char *S, size_t Start, char... C>
struct PastLastSlash<S, '/', Start, C...> {
constexpr auto operator()() {
return PastLastSlash<S, S[Start], Start + 1>()();
}
};
// Found the null-terminator, ends the search
template <const char *S, size_t Start, char... C>
struct PastLastSlash<S, '\0', Start, C...> {
constexpr auto operator()() {
return std::array<char, sizeof...(C)+1>{C..., '\0'};
}
};
}
template <const char *S>
struct PastLastSlash {
const char * operator()() {
static auto a = details::PastLastSlash<S, S[0], 0>()();
return a.data();
}
};
static constexpr char f[] = __FILE__;
int main() {
puts(PastLastSlash<f>{}());
return 0;
}
With C++20, it should be possible to pass __FILE__ directly to the template instead of needing those static constexpr variables

finding string format specifiers of variable argument list

I have this Log function that call my logger (spdlog) methods :
template<typename... Args>
void Log(const char* fmt,
const Args&... args)
{
g_FileLogger->log(fmt, args...);
}
I want to change my logger (spdlog, represented by g_FileLoggre) to another logger. Unfortunately, "fmt" strings contain "{}" which are the the placeholder of variables "args". I want to change those "{}" by the correct format specifier (%s, %zu, %d etc...) as with the other loggers, I have to specify the correct format specifier.
Can you give me a quick and safe solution to generate a string that replaces "{}" by the correct format specifier of the variables.
Otherwise, spdlog is a great logging API, but since its API has been broken, we decided to choose another logger, for example in Centos the API is old whereas in Gentoo it is newer and code will not compile.
Create a format_converter function
template<typename... Args>
std::string format_converter(const char* fmt,
const Args&... args)
{...}
which parses the fmt string and converts it according to the arguments.
Then modify your function:
template<typename... Args>
void Log(const char* fmt,
const Args&... args)
{
auto new_fmt = format_converter(fmt, args...);
new_logger->log( new_fmt, args... );
}
Edit:
In the format_converter, template functions can be used to convert the types of parameters to strings. For example:
template< typename T >
const char* type_string( const T ); // primary template
const char* type_string( const char* ) // overload for c-string
{
return "%s";
}
template<>
const char* type_string< double >( const double ) // partial specialization for double
{
return "%d";
}
template<>
const char* type_string< int >( const int ) // partial specialization for int
{
return "%i";
}
// .....
Create the convert_format function that will replace {..} with what you specify. Create a std::map<std::string, std::string> object that contains the data for replacing.
#include <string>
#include <map>
std::string convert_format(const std::string& format, std::map<std::string, std::string> format_map) {
string ret;
for (int x = 0; x != format.size(); ++x) {
if (format[x] == '{') {
std::string key;
++x;
for (; x != format.size(); ++x) {
if (format[x] == '}') {
auto itr = format_map.find(key);
if (itr != format_map.end()) {
ret += (*itr).second;
}
break;
} else {
key.push_back(format[x]);
}
}
} else {
ret.push_back(format[x]);
}
}
return ret;
}
And now modifies the Log function as:
template<typename... Args>
void Log(const char* fmt,
const Args&... args)
{
// map that will contain the data.
std::map<std::string, std::string> format_map;
// IF you have an args named as number and a string
// replaces {number} with %d
format_map["number"] = "%d";
// for replacing '{string}' with %s
format_map["string"] = "%s"; // ... and so on
auto new_fmt = convert_format(std::string(fmt), format_map);
new_logger->log( new_fmt, args... );
}
EDIT: I think you need a macro that will pass name and value of the variable to the function Log.

How does CUB's TexRefInputIterator work?

CUB provides an iterator for texture references, the implementation of which is readily accessible.
Since I couldn't figure out how to implement template-able texture references myself - they "can only be declared as a static global variable" - I am now trying to understand how it's done in CUB. But some of it is beyond my C++ knowledge, and I haven't been able to find the answers elsewhere (then again, I don't really know what to search for).
Specifically:
Is the unnamed namespace surrounding IteratorTexRef significant? I can only think that it is to limit IteratorTexRef::TexId::ref to file/translation unit scope.
What is the purpose of IteratorTexRef? It only wraps TexId, but removing it results in unintelligible (to me) compile-time errors.
This code, a stripped-down version of the linked-to implementation, compiles and runs:
#include <thrust/device_vector.h>
namespace {
template <typename T>
struct IteratorTexRef
{
template <int UNIQUE_ID>
struct TexId
{
// Assume T is a valid texture word size.
typedef texture<T> TexRef;
static TexRef ref;
static __device__ T fetch(ptrdiff_t offset)
{
return tex1Dfetch(ref, offset);
}
};
};
template <typename T>
template <int UNIQUE_ID>
typename IteratorTexRef<T>:: template TexId<UNIQUE_ID>::TexRef IteratorTexRef<T>:: template TexId<UNIQUE_ID>::ref;
} // Anomymous namespace
template <typename T, int UNIQUE_ID = 0>
class TextureRefIterator
{
private:
typedef typename IteratorTexRef<T>:: template TexId<UNIQUE_ID> TexId;
ptrdiff_t tex_offset;
public:
__device__ T operator[](int i) const
{
return TexId::fetch(this->tex_offset + i);
}
cudaError_t bind(
const T* const ptr,
size_t bytes = size_t(-1))
{
size_t offset;
cudaError_t state = cudaBindTexture(&offset, TexId::ref, ptr, bytes);
this->tex_offset = (ptrdiff_t) (offset / sizeof(T));
return state;
}
};
template <typename TexIter>
__global__ void kernel(TexIter iter)
{
int a = iter[threadIdx.x];
printf("tid %d, a %d\n", threadIdx.x, a);
}
template <typename T>
void launch_kernel(T* d_in)
{
TextureRefIterator<T> tex_iter;
tex_iter.bind(d_in);
kernel<<<1, 32>>>(tex_iter);
}
int main()
{
thrust::device_vector<float> d_in(32, 1);
launch_kernel(thrust::raw_pointer_cast(d_in.data()));
}
The closest I got was something similar to the below, based on how one would normally access a static template member. For clarity, the below simply eliminates IteratorTexRef from the above:
#include <thrust/device_vector.h>
namespace {
template <typename T, int UNIQUE_ID>
struct TexId
{
// Assume T is a valid texture word size.
typedef texture<T> TexRef;
static TexRef ref;
static __device__ T fetch(ptrdiff_t offset)
{
return tex1Dfetch(ref, offset);
}
};
template <typename T, int UNIQUE_ID>
typename TexId<T, UNIQUE_ID>::TexRef TexId<T, UNIQUE_ID>::ref;
} // Anonymous namespace
template <typename T, int UNIQUE_ID = 0>
class TextureRefIterator
{
private:
typedef TexId<T, UNIQUE_ID> TexId;
ptrdiff_t tex_offset;
public:
__device__ T operator[](int i) const
{
return TexId::fetch(this->tex_offset + i);
}
cudaError_t bind(
const T* const ptr,
size_t bytes = size_t(-1))
{
size_t offset;
cudaError_t state = cudaBindTexture(&offset, TexId::ref, ptr, bytes);
this->tex_offset = (ptrdiff_t) (offset / sizeof(T));
return state;
}
};
template <typename TexIter>
__global__ void kernel(TexIter iter)
{
int a = iter[0];
printf("tid %d, a %d\n", threadIdx.x, a);
}
template <typename T>
void launch_kernel(T* d_in)
{
TextureRefIterator<T> tex_iter;
tex_iter.bind(d_in);
kernel<<<1, 32>>>(tex_iter);
}
int main()
{
thrust::device_vector<float> d_in(32, 1);
launch_kernel(thrust::raw_pointer_cast(d_in.data()));
}
It gives these somewhat esoteric compile-time errors. (Compiled with nvcc iter.cu and CUDA 7.0):
In file included from tmpxft_000057d4_00000000-4_test2.cudafe1.stub.c:1:0:
/tmp/tmpxft_000057d4_00000000-4_test2.cudafe1.stub.c:30:3737: error: macro "__text_var" passed 3 arguments, but takes just 2
dIfLi0EE3refE,::_NV_ANON_NAMESPACE::TexId<float, (int)0> ::ref), 1, 0, 0);__cudaReg
^
/tmp/tmpxft_000057d4_00000000-4_test2.cudafe1.stub.c:30:1: error: macro "__device__text_var" passed 3 arguments, but takes just 2
static void __nv_cudaEntityRegisterCallback(void **__T2202){__nv_dummy_param_ref(__
^
/tmp/tmpxft_000057d4_00000000-4_test2.cudafe1.stub.c:30:1: error: macro "__name__text_var" passed 3 arguments, but takes just 2
That compile error is due to the generated code using macros that contain template types so the commas in the templates make the preprocessor think that that they are more arguments. I fixed this by patching the crt/host_runtime header and making the cpp parameter of those macros (__text_var, __device__text_var, and __name__text_var) variadic. In other words, replace cpp with cpp....

Is it possible to build a "filtered tuple" or "filtered parameter pack" from a template parameter pack?

I have a situation where I want to call some function on each value in a template parameter pack, and store the result of calling that function in a stack-allocated variable. For instance:
#include <string>
#include <utility>
#include <functional>
char const* format_value(double x) { /* ... */ }
std::string format_value(long x) { /* ... */ }
template <typename Sink, typename... Values>
Sink& format(Sink& target, Values... values)
{
// Does not compile; Not valid C++11
typedef std::tuple<typename std::result_of<format_value(values)>::type...> tuple_type;
tuple_type slices(format_value(values)...);
/* Code that does things with the results. */
}
Is it possible to do this sort of filtering, and if so, how do I do it?
Alright. I saw your code at github and hopefully know what you're trying to achieve.
I think you can still avoid the recursive call to format_buffer(). Here is the part I'm talking about:
template <typename Slice, typename... Slices>
char const* format_buffer(char* ptr, std::size_t length, Slice const& slice, Slices const& ...slices)
{
std::size_t const size = slice.size();
std::copy_n(slice.data(), size, ptr);
return format_buffer(ptr + size, length - size, slices...);
}
template <typename Sink, typename... Slices>
Sink& write_impl(Sink& target, Slices &&...slices)
{
std::size_t const length = sum_sizes(slices...);
OptimisticBuffer<256> buff(length);
char* ptr = buff.GetAs<char>();
char const* endPtr = format_buffer(ptr, length, slices...);
target.append(ptr, endPtr - ptr);
return target;
}
Can be replaced with this:
struct unpack { template<typename ...T> unpack(T && ...) {} };
template <typename Sink, typename... Slices>
Sink& write_impl(Sink& target, Slices &&...slices)
{
std::size_t const length = sum_sizes(slices...);
OptimisticBuffer<256> buff(length);
char* ptr = buff.GetAs<char>();
char *origin = ptr;
unpack { (ptr = std::copy_n(slices.data(), slices.size(), ptr)) ... } ;
target.append(origin, ptr - origin);
return target;
}
The magic happens at unpack {} line. For each slice in slices, you call std::copy_n which returns ptr+size (which is then stored in ptr) which becomes the input for the next call to std::copy_n and so on:
unpack { (ptr = std::copy_n(slices.data(), slices.size(), ptr)) ... } ;
expands to this:
unpack
{
(ptr = std::copy_n(slices0.data(), slices0.size(), ptr)),
(ptr = std::copy_n(slices1.data(), slices1.size(), ptr)),
(ptr = std::copy_n(slices2.data(), slices2.size(), ptr)),
.
.
(ptr = std::copy_n(slicesN.data(), slicesN.size(), ptr)),
};
Note that since it uses list-initialization, the order of evaluation of expressions is guaranteed to be left-to-right, i.e top-to-down in the expanded form!
Since GCC has bug since 4.7.0 (which is why currently it doesn't work), you can write this:
using unpack = void const*[];
unpack {(ptr=std::copy_n(slicesN.data(),slicesN.size(), ptr))...};`
Another improvement would be this: instead of sum_sizes(), I would implement sum so that instead of this:
std::size_t const length = sum_sizes(slices...);
I could write this:
std::size_t const length = sum(slices.size()...);
In this way, sum() would be more reusable, like:
std::size_t const x = sum(args.get_element_size()...);
std::size_t const y = sum(sizeof(Ts)...);
if you ever need these. Well, in case of sizeof, a compile-time sum<> would be better — though the point remains same, sum is more reusable than sum_sizes().
You can use auto and a function which accepts a parameter pack to generate the requisite tuple. For instance, std::make_tuple works just fine:
#include <string>
#include <utility>
char const* format_value(double x) { /* ... */ }
std::string format_value(long x) { /* ... */ }
template <typename Sink, typename... Values>
Sink& format(Sink& target, Values... values)
{
auto slices = std::make_tuple(format_value(values)...);
/* Code that does things with the results. */
}
Similarly, you may also be able to avoid using tuple altogether by forwarding to another function. For instance:
#include <string>
char const* format_value(double x) { /* ... */ }
std::string format_value(long x) { /* ... */ }
template <typename Sink, typename... Results>
void format_impl(Sink& target, Results... results)
{
/* Code that does things with the results. */
}
template <typename Sink, typename... Values>
Sink& format(Sink& target, Values... values)
{
format_impl(target, format_value(values)...);
return sink;
}

Conveniently Declaring Compile-Time Strings in C++

Being able to create and manipulate strings during compile-time in C++ has several useful applications. Although it is possible to create compile-time strings in C++, the process is very cumbersome, as the string needs to be declared as a variadic sequence of characters, e.g.
using str = sequence<'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'>;
Operations such as string concatenation, substring extraction, and many others, can easily be implemented as operations on sequences of characters. Is it possible to declare compile-time strings more conveniently? If not, is there a proposal in the works that would allow for convenient declaration of compile-time strings?
Why Existing Approaches Fail
Ideally, we would like to be able to declare compile-time strings as follows:
// Approach 1
using str1 = sequence<"Hello, world!">;
or, using user-defined literals,
// Approach 2
constexpr auto str2 = "Hello, world!"_s;
where decltype(str2) would have a constexpr constructor. A messier version of approach 1 is possible to implement, taking advantage of the fact that you can do the following:
template <unsigned Size, const char Array[Size]>
struct foo;
However, the array would need to have external linkage, so to get approach 1 to work, we would have to write something like this:
/* Implementation of array to sequence goes here. */
constexpr const char str[] = "Hello, world!";
int main()
{
using s = string<13, str>;
return 0;
}
Needless to say, this is very inconvenient. Approach 2 is actually not possible to implement. If we were to declare a (constexpr) literal operator, then how would we specify the return type? Since we need the operator to return a variadic sequence of characters, so we would need to use the const char* parameter to specify the return type:
constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */
This results in a compile error, because s is not a constexpr. Trying to work around this by doing the following does not help much.
template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }
The standard dictates that this specific literal operator form is reserved for integer and floating-point types. While 123_s would work, abc_s would not. What if we ditch user-defined literals altogether, and just use a regular constexpr function?
template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */
As before, we run into the problem that the array, now a parameter to the constexpr function, is itself no longer a constexpr type.
I believe it should be possible to define a C preprocessor macro that takes a string and the size of the string as arguments, and returns a sequence consisting of the characters in the string (using BOOST_PP_FOR, stringification, array subscripts, and the like). However, I do not have the time (or enough interest) to implement such a macro =)
I haven't seen anything to match the elegance of Scott Schurr's str_const presented at C++ Now 2012. It does require constexpr though.
Here's how you can use it, and what it can do:
int
main()
{
constexpr str_const my_string = "Hello, world!";
static_assert(my_string.size() == 13, "");
static_assert(my_string[4] == 'o', "");
constexpr str_const my_other_string = my_string;
static_assert(my_string == my_other_string, "");
constexpr str_const world(my_string, 7, 5);
static_assert(world == "world", "");
// constexpr char x = world[5]; // Does not compile because index is out of range!
}
It doesn't get much cooler than compile-time range checking!
Both the use, and the implementation, is free of macros. And there is no artificial limit on string size. I'd post the implementation here, but I'm respecting Scott's implicit copyright. The implementation is on a single slide of his presentation linked to above.
Update C++17
In the years since I posted this answer, std::string_view has become part of our tool chest. Here is how I would rewrite the above using string_view:
#include <string_view>
int
main()
{
constexpr std::string_view my_string = "Hello, world!";
static_assert(my_string.size() == 13);
static_assert(my_string[4] == 'o');
constexpr std::string_view my_other_string = my_string;
static_assert(my_string == my_other_string);
constexpr std::string_view world(my_string.substr(7, 5));
static_assert(world == "world");
// constexpr char x = world.at(5); // Does not compile because index is out of range!
}
I believe it should be possible to define a C preprocessor macro that
takes a string and the size of the string as arguments, and returns a
sequence consisting of the characters in the string (using
BOOST_PP_FOR, stringification, array subscripts, and the like).
However, I do not have the time (or enough interest) to implement such
a macro
it is possible to implement this without relying on boost, using very simple macro and some of C++11 features:
lambdas variadic
templates
generalized constant expressions
non-static data member initializers
uniform initialization
(the latter two are not strictly required here)
we need to be able to instantiate a variadic template with user supplied indicies from 0 to N - a tool also useful for example to expand tuple into variadic template function's argument (see questions: How do I expand a tuple into variadic template function's arguments?
"unpacking" a tuple to call a matching function pointer)
namespace variadic_toolbox
{
template<unsigned count,
template<unsigned...> class meta_functor, unsigned... indices>
struct apply_range
{
typedef typename apply_range<count-1, meta_functor, count-1, indices...>::result result;
};
template<template<unsigned...> class meta_functor, unsigned... indices>
struct apply_range<0, meta_functor, indices...>
{
typedef typename meta_functor<indices...>::result result;
};
}
then define a variadic template called string with non-type
parameter char:
namespace compile_time
{
template<char... str>
struct string
{
static constexpr const char chars[sizeof...(str)+1] = {str..., '\0'};
};
template<char... str>
constexpr const char string<str...>::chars[sizeof...(str)+1];
}
now the most interesting part - to pass character literals into string
template:
namespace compile_time
{
template<typename lambda_str_type>
struct string_builder
{
template<unsigned... indices>
struct produce
{
typedef string<lambda_str_type{}.chars[indices]...> result;
};
};
}
#define CSTRING(string_literal) \
[]{ \
struct constexpr_string_type { const char * chars = string_literal; }; \
return variadic_toolbox::apply_range<sizeof(string_literal)-1, \
compile_time::string_builder<constexpr_string_type>::produce>::result{}; \
}()
a simple concatenation demonstration shows the usage:
namespace compile_time
{
template<char... str0, char... str1>
string<str0..., str1...> operator*(string<str0...>, string<str1...>)
{
return {};
}
}
int main()
{
auto str0 = CSTRING("hello");
auto str1 = CSTRING(" world");
std::cout << "runtime concat: " << str_hello.chars << str_world.chars << "\n <=> \n";
std::cout << "compile concat: " << (str_hello * str_world).chars << std::endl;
}
https://ideone.com/8Ft2xu
Edit: as Howard Hinnant (and me somewhat in my comment to the OP) pointed out, you might not need a type with every single character of the string as a single template argument.
If you do need this, there's a macro-free solution below.
There's a trick I found while trying to work with strings at compile time. It requires to introduce another type besides the "template string", but within functions, you can limit the scope of this type.
It doesn't use macros but rather some C++11 features.
#include <iostream>
// helper function
constexpr unsigned c_strlen( char const* str, unsigned count = 0 )
{
return ('\0' == str[0]) ? count : c_strlen(str+1, count+1);
}
// destination "template string" type
template < char... chars >
struct exploded_string
{
static void print()
{
char const str[] = { chars... };
std::cout.write(str, sizeof(str));
}
};
// struct to explode a `char const*` to an `exploded_string` type
template < typename StrProvider, unsigned len, char... chars >
struct explode_impl
{
using result =
typename explode_impl < StrProvider, len-1,
StrProvider::str()[len-1],
chars... > :: result;
};
// recursion end
template < typename StrProvider, char... chars >
struct explode_impl < StrProvider, 0, chars... >
{
using result = exploded_string < chars... >;
};
// syntactical sugar
template < typename StrProvider >
using explode =
typename explode_impl < StrProvider,
c_strlen(StrProvider::str()) > :: result;
int main()
{
// the trick is to introduce a type which provides the string, rather than
// storing the string itself
struct my_str_provider
{
constexpr static char const* str() { return "hello world"; }
};
auto my_str = explode < my_str_provider >{}; // as a variable
using My_Str = explode < my_str_provider >; // as a type
my_str.print();
}
If you don't want to use the Boost solution you can create simple macros that will do something similar:
#define MACRO_GET_1(str, i) \
(sizeof(str) > (i) ? str[(i)] : 0)
#define MACRO_GET_4(str, i) \
MACRO_GET_1(str, i+0), \
MACRO_GET_1(str, i+1), \
MACRO_GET_1(str, i+2), \
MACRO_GET_1(str, i+3)
#define MACRO_GET_16(str, i) \
MACRO_GET_4(str, i+0), \
MACRO_GET_4(str, i+4), \
MACRO_GET_4(str, i+8), \
MACRO_GET_4(str, i+12)
#define MACRO_GET_64(str, i) \
MACRO_GET_16(str, i+0), \
MACRO_GET_16(str, i+16), \
MACRO_GET_16(str, i+32), \
MACRO_GET_16(str, i+48)
#define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0 //guard for longer strings
using seq = sequence<MACRO_GET_STR("Hello world!")>;
The only problem is the fixed size of 64 chars (plus additional zero). But it can easily be changed depending on your needs.
I believe it should be possible to define a C preprocessor macro that takes a string and the size of the string as arguments, and returns a sequence consisting of the characters in the string (using BOOST_PP_FOR, stringification, array subscripts, and the like)
There is article: Using strings in C++ template metaprograms by Abel Sinkovics and Dave Abrahams.
It has some improvement over your idea of using macro + BOOST_PP_REPEAT - it doesn't require passing explicit size to macro. In short, it is based on fixed upper limit for string size and "string overrun protection":
template <int N>
constexpr char at(char const(&s)[N], int i)
{
return i >= N ? '\0' : s[i];
}
plus conditional boost::mpl::push_back.
I changed my accepted answer to Yankes' solution, since it solves this specific problem, and does so elegantly without the use of constexpr or complex preprocessor code.
If you accept trailing zeros, hand-written macro looping, 2x repetion of string in expanded macro, and don't have Boost - then I agree - it is better. Though, with Boost it would be just three lines:
LIVE DEMO
#include <boost/preprocessor/repetition/repeat.hpp>
#define GET_STR_AUX(_, i, str) (sizeof(str) > (i) ? str[(i)] : 0),
#define GET_STR(str) BOOST_PP_REPEAT(64,GET_STR_AUX,str) 0
Here's a succinct C++14 solution to creating a std::tuple<char...> for each compile-time string passed.
#include <tuple>
#include <utility>
namespace detail {
template <std::size_t ... indices>
decltype(auto) build_string(const char * str, std::index_sequence<indices...>) {
return std::make_tuple(str[indices]...);
}
}
template <std::size_t N>
constexpr decltype(auto) make_string(const char(&str)[N]) {
return detail::build_string(str, std::make_index_sequence<N>());
}
auto HelloStrObject = make_string("hello");
And here's one for creating a unique compile-time type, trimmed down from the other macro post.
#include <utility>
template <char ... Chars>
struct String {};
template <typename Str, std::size_t ... indices>
decltype(auto) build_string(std::index_sequence<indices...>) {
return String<Str().chars[indices]...>();
}
#define make_string(str) []{\
struct Str { const char * chars = str; };\
return build_string<Str>(std::make_index_sequence<sizeof(str)>());\
}()
auto HelloStrObject = make_string("hello");
It's really too bad that user-defined literals can't be used for this yet.
A colleague challenged me to concatenate strings in memory at compile-time. It includes instantiating individual strings at compile-time as well. The full code listing is here:
//Arrange strings contiguously in memory at compile-time from string literals.
//All free functions prefixed with "my" to faciliate grepping the symbol tree
//(none of them should show up).
#include <iostream>
using std::size_t;
//wrapper for const char* to "allocate" space for it at compile-time
template<size_t N>
struct String {
//C arrays can only be initialised with a comma-delimited list
//of values in curly braces. Good thing the compiler expands
//parameter packs into comma-delimited lists. Now we just have
//to get a parameter pack of char into the constructor.
template<typename... Args>
constexpr String(Args... args):_str{ args... } { }
const char _str[N];
};
//takes variadic number of chars, creates String object from it.
//i.e. myMakeStringFromChars('f', 'o', 'o', '\0') -> String<4>::_str = "foo"
template<typename... Args>
constexpr auto myMakeStringFromChars(Args... args) -> String<sizeof...(Args)> {
return String<sizeof...(args)>(args...);
}
//This struct is here just because the iteration is going up instead of
//down. The solution was to mix traditional template metaprogramming
//with constexpr to be able to terminate the recursion since the template
//parameter N is needed in order to return the right-sized String<N>.
//This class exists only to dispatch on the recursion being finished or not.
//The default below continues recursion.
template<bool TERMINATE>
struct RecurseOrStop {
template<size_t N, size_t I, typename... Args>
static constexpr String<N> recurseOrStop(const char* str, Args... args);
};
//Specialisation to terminate recursion when all characters have been
//stripped from the string and converted to a variadic template parameter pack.
template<>
struct RecurseOrStop<true> {
template<size_t N, size_t I, typename... Args>
static constexpr String<N> recurseOrStop(const char* str, Args... args);
};
//Actual function to recurse over the string and turn it into a variadic
//parameter list of characters.
//Named differently to avoid infinite recursion.
template<size_t N, size_t I = 0, typename... Args>
constexpr String<N> myRecurseOrStop(const char* str, Args... args) {
//template needed after :: since the compiler needs to distinguish
//between recurseOrStop being a function template with 2 paramaters
//or an enum being compared to N (recurseOrStop < N)
return RecurseOrStop<I == N>::template recurseOrStop<N, I>(str, args...);
}
//implementation of the declaration above
//add a character to the end of the parameter pack and recurse to next character.
template<bool TERMINATE>
template<size_t N, size_t I, typename... Args>
constexpr String<N> RecurseOrStop<TERMINATE>::recurseOrStop(const char* str,
Args... args) {
return myRecurseOrStop<N, I + 1>(str, args..., str[I]);
}
//implementation of the declaration above
//terminate recursion and construct string from full list of characters.
template<size_t N, size_t I, typename... Args>
constexpr String<N> RecurseOrStop<true>::recurseOrStop(const char* str,
Args... args) {
return myMakeStringFromChars(args...);
}
//takes a compile-time static string literal and returns String<N> from it
//this happens by transforming the string literal into a variadic paramater
//pack of char.
//i.e. myMakeString("foo") -> calls myMakeStringFromChars('f', 'o', 'o', '\0');
template<size_t N>
constexpr String<N> myMakeString(const char (&str)[N]) {
return myRecurseOrStop<N>(str);
}
//Simple tuple implementation. The only reason std::tuple isn't being used
//is because its only constexpr constructor is the default constructor.
//We need a constexpr constructor to be able to do compile-time shenanigans,
//and it's easier to roll our own tuple than to edit the standard library code.
//use MyTupleLeaf to construct MyTuple and make sure the order in memory
//is the same as the order of the variadic parameter pack passed to MyTuple.
template<typename T>
struct MyTupleLeaf {
constexpr MyTupleLeaf(T value):_value(value) { }
T _value;
};
//Use MyTupleLeaf implementation to define MyTuple.
//Won't work if used with 2 String<> objects of the same size but this
//is just a toy implementation anyway. Multiple inheritance guarantees
//data in the same order in memory as the variadic parameters.
template<typename... Args>
struct MyTuple: public MyTupleLeaf<Args>... {
constexpr MyTuple(Args... args):MyTupleLeaf<Args>(args)... { }
};
//Helper function akin to std::make_tuple. Needed since functions can deduce
//types from parameter values, but classes can't.
template<typename... Args>
constexpr MyTuple<Args...> myMakeTuple(Args... args) {
return MyTuple<Args...>(args...);
}
//Takes a variadic list of string literals and returns a tuple of String<> objects.
//These will be contiguous in memory. Trailing '\0' adds 1 to the size of each string.
//i.e. ("foo", "foobar") -> (const char (&arg1)[4], const char (&arg2)[7]) params ->
// -> MyTuple<String<4>, String<7>> return value
template<size_t... Sizes>
constexpr auto myMakeStrings(const char (&...args)[Sizes]) -> MyTuple<String<Sizes>...> {
//expands into myMakeTuple(myMakeString(arg1), myMakeString(arg2), ...)
return myMakeTuple(myMakeString(args)...);
}
//Prints tuple of strings
template<typename T> //just to avoid typing the tuple type of the strings param
void printStrings(const T& strings) {
//No std::get or any other helpers for MyTuple, so intead just cast it to
//const char* to explore its layout in memory. We could add iterators to
//myTuple and do "for(auto data: strings)" for ease of use, but the whole
//point of this exercise is the memory layout and nothing makes that clearer
//than the ugly cast below.
const char* const chars = reinterpret_cast<const char*>(&strings);
std::cout << "Printing strings of total size " << sizeof(strings);
std::cout << " bytes:\n";
std::cout << "-------------------------------\n";
for(size_t i = 0; i < sizeof(strings); ++i) {
chars[i] == '\0' ? std::cout << "\n" : std::cout << chars[i];
}
std::cout << "-------------------------------\n";
std::cout << "\n\n";
}
int main() {
{
constexpr auto strings = myMakeStrings("foo", "foobar",
"strings at compile time");
printStrings(strings);
}
{
constexpr auto strings = myMakeStrings("Some more strings",
"just to show Jeff to not try",
"to challenge C++11 again :P",
"with more",
"to show this is variadic");
printStrings(strings);
}
std::cout << "Running 'objdump -t |grep my' should show that none of the\n";
std::cout << "functions defined in this file (except printStrings()) are in\n";
std::cout << "the executable. All computations are done by the compiler at\n";
std::cout << "compile-time. printStrings() executes at run-time.\n";
}
Nobody seems to like my other answer :-<. So here I show how to convert a str_const to a real type:
#include <iostream>
#include <utility>
// constexpr string with const member functions
class str_const {
private:
const char* const p_;
const std::size_t sz_;
public:
template<std::size_t N>
constexpr str_const(const char(&a)[N]) : // ctor
p_(a), sz_(N-1) {}
constexpr char operator[](std::size_t n) const {
return n < sz_ ? p_[n] :
throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz_; } // size()
};
template <char... letters>
struct string_t{
static char const * c_str() {
static constexpr char string[]={letters...,'\0'};
return string;
}
};
template<str_const const& str,std::size_t... I>
auto constexpr expand(std::index_sequence<I...>){
return string_t<str[I]...>{};
}
template<str_const const& str>
using string_const_to_type = decltype(expand<str>(std::make_index_sequence<str.size()>{}));
constexpr str_const hello{"Hello World"};
using hello_t = string_const_to_type<hello>;
int main()
{
// char c = hello_t{}; // Compile error to print type
std::cout << hello_t::c_str();
return 0;
}
Compiles with clang++ -stdlib=libc++ -std=c++14 (clang 3.7)
Your approach #1 is the correct one.
However, the array would need to have external linkage, so to get approach 1 to work, we would have to write something like this:
constexpr const char str[] = "Hello, world!";
No, not correct. This compiles with clang and gcc. I hope its standard c++11, but i am not a language laywer.
#include <iostream>
template <char... letters>
struct string_t{
static char const * c_str() {
static constexpr char string[]={letters...,'\0'};
return string;
}
};
// just live with it, but only once
using Hello_World_t = string_t<'H','e','l','l','o',' ','w','o','r','l','d','!'>;
template <typename Name>
void print()
{
//String as template parameter
std::cout << Name::c_str();
}
int main() {
std::cout << Hello_World_t::c_str() << std::endl;
print<Hello_World_t>();
return 0;
}
What I would really love for c++17 would be the following to be equivalent (to complete approach #1)
// for template <char...>
<"Text"> == <'T','e','x','t'>
Something very similar already exists in the standard for templated user defined literals,as void-pointer also mentions, but only for digits.
Until then another little trick is to use the override editing mode + copy and paste of
string_t<' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '>;
If you do not mind the macro, than this works(slighty modified from Yankes answer):
#define MACRO_GET_1(str, i) \
(sizeof(str) > (i) ? str[(i)] : 0)
#define MACRO_GET_4(str, i) \
MACRO_GET_1(str, i+0), \
MACRO_GET_1(str, i+1), \
MACRO_GET_1(str, i+2), \
MACRO_GET_1(str, i+3)
#define MACRO_GET_16(str, i) \
MACRO_GET_4(str, i+0), \
MACRO_GET_4(str, i+4), \
MACRO_GET_4(str, i+8), \
MACRO_GET_4(str, i+12)
#define MACRO_GET_64(str, i) \
MACRO_GET_16(str, i+0), \
MACRO_GET_16(str, i+16), \
MACRO_GET_16(str, i+32), \
MACRO_GET_16(str, i+48)
//CT_STR means Compile-Time_String
#define CT_STR(str) string_t<MACRO_GET_64(#str, 0), 0 >//guard for longer strings
print<CT_STR(Hello World!)>();
kacey's solution for creating a unique compile-time type can, with minor modifications, also be used with C++11:
template <char... Chars>
struct string_t {};
namespace detail {
template <typename Str,unsigned int N,char... Chars>
struct make_string_t : make_string_t<Str,N-1,Str().chars[N-1],Chars...> {};
template <typename Str,char... Chars>
struct make_string_t<Str,0,Chars...> { typedef string_t<Chars...> type; };
} // namespace detail
#define CSTR(str) []{ \
struct Str { const char *chars = str; }; \
return detail::make_string_t<Str,sizeof(str)>::type(); \
}()
Use:
template <typename String>
void test(String) {
// ... String = string_t<'H','e','l','l','o','\0'>
}
test(CSTR("Hello"));
While playing with the boost hana map, I came across this thread. As non of the answers solved my problem, I found a different solution which I want to add here as it could be potentially helpful for others.
My problem was that when using the boost hana map with hana strings, the compiler still generated some runtime code (see below). The reason was obviously that to query the map at compile-time it must be constexpr. This isn't possible as the BOOST_HANA_STRING macro generates a lambda, which can't be used in constexpr context. On the other hand, the map needs strings with different content to be different types.
As the solutions in this thread are either using a lambda or not providing different types for different contents, I found the following approach helpful. Also it avoids the hacky str<'a', 'b', 'c'> syntax.
The basic idea is having a version of Scott Schurr's str_const templated on the hash of the characters. It is c++14, but c++11 should be possible with a recursive implementation of the crc32 function (see here).
// str_const from https://github.com/boostcon/cppnow_presentations_2012/blob/master/wed/schurr_cpp11_tools_for_class_authors.pdf?raw=true
#include <string>
template<unsigned Hash> ////// <- This is the difference...
class str_const2 { // constexpr string
private:
const char* const p_;
const std::size_t sz_;
public:
template<std::size_t N>
constexpr str_const2(const char(&a)[N]) : // ctor
p_(a), sz_(N - 1) {}
constexpr char operator[](std::size_t n) const { // []
return n < sz_ ? p_[n] :
throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz_; } // size()
constexpr const char* const data() const {
return p_;
}
};
// Crc32 hash function. Non-recursive version of https://stackoverflow.com/a/23683218/8494588
static constexpr unsigned int crc_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
template<size_t N>
constexpr auto crc32(const char(&str)[N])
{
unsigned int prev_crc = 0xFFFFFFFF;
for (auto idx = 0; idx < sizeof(str) - 1; ++idx)
prev_crc = (prev_crc >> 8) ^ crc_table[(prev_crc ^ str[idx]) & 0xFF];
return prev_crc ^ 0xFFFFFFFF;
}
// Conveniently create a str_const2
#define CSTRING(text) str_const2 < crc32( text ) >( text )
// Conveniently create a hana type_c<str_const2> for use in map
#define CSTRING_TYPE(text) hana::type_c<decltype(str_const2 < crc32( text ) >( text ))>
Usage:
#include <boost/hana.hpp>
#include <boost/hana/map.hpp>
#include <boost/hana/pair.hpp>
#include <boost/hana/type.hpp>
namespace hana = boost::hana;
int main() {
constexpr auto s2 = CSTRING("blah");
constexpr auto X = hana::make_map(
hana::make_pair(CSTRING_TYPE("aa"), 1)
);
constexpr auto X2 = hana::insert(X, hana::make_pair(CSTRING_TYPE("aab"), 2));
constexpr auto ret = X2[(CSTRING_TYPE("aab"))];
return ret;
}
Resulting assembler code with clang-cl 5.0 is:
012A1370 mov eax,2
012A1375 ret
In C++17 with a helper macro function it's easy to create compile time strings:
template <char... Cs>
struct ConstexprString
{
static constexpr int size = sizeof...( Cs );
static constexpr char buffer[size] = { Cs... };
};
template <char... C1, char... C2>
constexpr bool operator==( const ConstexprString<C1...>& lhs, const ConstexprString<C2...>& rhs )
{
if( lhs.size != rhs.size )
return false;
return std::is_same_v<std::integer_sequence<char, C1...>, std::integer_sequence<char, C2...>>;
}
template <typename F, std::size_t... Is>
constexpr auto ConstexprStringBuilder( F f, std::index_sequence<Is...> )
{
return ConstexprString<f( Is )...>{};
}
#define CONSTEXPR_STRING( x ) \
ConstexprStringBuilder( []( std::size_t i ) constexpr { return x[i]; }, \
std::make_index_sequence<sizeof(x)>{} )
And this is a usage example:
auto n = CONSTEXPR_STRING( "ab" );
auto m = CONSTEXPR_STRING( "ab" );
static_assert(n == m);
based on idea from Howard Hinnant you can create literal class that will add two literals together.
template<int>
using charDummy = char;
template<int... dummy>
struct F
{
const char table[sizeof...(dummy) + 1];
constexpr F(const char* a) : table{ str_at<dummy>(a)..., 0}
{
}
constexpr F(charDummy<dummy>... a) : table{ a..., 0}
{
}
constexpr F(const F& a) : table{ a.table[dummy]..., 0}
{
}
template<int... dummyB>
constexpr F<dummy..., sizeof...(dummy)+dummyB...> operator+(F<dummyB...> b)
{
return { this->table[dummy]..., b.table[dummyB]... };
}
};
template<int I>
struct get_string
{
constexpr static auto g(const char* a) -> decltype( get_string<I-1>::g(a) + F<0>(a + I))
{
return get_string<I-1>::g(a) + F<0>(a + I);
}
};
template<>
struct get_string<0>
{
constexpr static F<0> g(const char* a)
{
return {a};
}
};
template<int I>
constexpr auto make_string(const char (&a)[I]) -> decltype( get_string<I-2>::g(a) )
{
return get_string<I-2>::g(a);
}
constexpr auto a = make_string("abc");
constexpr auto b = a+ make_string("def"); // b.table == "abcdef"
I'd like to add two very small improvements to the answer of #user1115339. I mentioned them in the comments to the answer, but for convenience I'll put a copy paste solution here.
The only difference is the FIXED_CSTRING macro, which allows to use the strings within class templates and as arguments to the index operator (useful if you have e.g. a compiletime map).
Live example.
namespace variadic_toolbox
{
template<unsigned count,
template<unsigned...> class meta_functor, unsigned... indices>
struct apply_range
{
typedef typename apply_range<count-1, meta_functor, count-1, indices...>::result result;
};
template<template<unsigned...> class meta_functor, unsigned... indices>
struct apply_range<0, meta_functor, indices...>
{
typedef typename meta_functor<indices...>::result result;
};
}
namespace compile_time
{
template<char... str>
struct string
{
static constexpr const char chars[sizeof...(str)+1] = {str..., '\0'};
};
template<char... str>
constexpr const char string<str...>::chars[sizeof...(str)+1];
template<typename lambda_str_type>
struct string_builder
{
template<unsigned... indices>
struct produce
{
typedef string<lambda_str_type{}.chars[indices]...> result;
};
};
}
#define CSTRING(string_literal) \
[]{ \
struct constexpr_string_type { const char * chars = string_literal; }; \
return variadic_toolbox::apply_range<sizeof(string_literal)-1, \
compile_time::string_builder<constexpr_string_type>::produce>::result{}; \
}()
#define FIXED_CSTRING(string_literal) \
([]{ \
struct constexpr_string_type { const char * chars = string_literal; }; \
return typename variadic_toolbox::apply_range<sizeof(string_literal)-1, \
compile_time::string_builder<constexpr_string_type>::template produce>::result{}; \
}())
struct A {
auto test() {
return FIXED_CSTRING("blah"); // works
// return CSTRING("blah"); // works too
}
template<typename X>
auto operator[](X) {
return 42;
}
};
template<typename T>
struct B {
auto test() {
// return CSTRING("blah");// does not compile
return FIXED_CSTRING("blah"); // works
}
};
int main() {
A a;
//return a[CSTRING("blah")]; // fails with error: two consecutive ' [ ' shall only introduce an attribute before ' [ ' token
return a[FIXED_CSTRING("blah")];
}
My own implementation is based on approach from the Boost.Hana string (template class with variadic characters), but utilizes only the C++11 standard and constexpr functions with strict check on compiletimeness (would be a compile time error if not a compile time expression). Can be constructed from the usual raw C string instead of fancy {'a', 'b', 'c' } (through a macro).
Implementation:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/include/tacklelib/tackle/tmpl_string.hpp
Tests:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/src/tests/unit/test_tmpl_string.cpp
Usage examples:
const auto s0 = TACKLE_TMPL_STRING(0, "012"); // "012"
const char c1_s0 = UTILITY_CONSTEXPR_GET(s0, 1); // '1'
const auto s1 = TACKLE_TMPL_STRING(0, "__012", 2); // "012"
const char c1_s1 = UTILITY_CONSTEXPR_GET(s1, 1); // '1'
const auto s2 = TACKLE_TMPL_STRING(0, "__012__", 2, 3); // "012"
const char c1_s2 = UTILITY_CONSTEXPR_GET(s2, 1); // '1'
// TACKLE_TMPL_STRING(0, "012") and TACKLE_TMPL_STRING(1, "012")
// - semantically having different addresses.
// So id can be used to generate new static array class field to store
// a string bytes at different address.
// Can be overloaded in functions with another type to express the compiletimeness between functions:
template <uint64_t id, typename CharT, CharT... tchars>
const overload_resolution_1 & test_overload_resolution(const tackle::tmpl_basic_string<id, CharT, tchars...> &);
template <typename CharT>
const overload_resolution_2 & test_overload_resolution(const tackle::constexpr_basic_string<CharT> &);
// , where `constexpr_basic_string` is another approach which loses
// the compiletimeness between function signature and body border,
// because even in a `constexpr` function the compile time argument
// looses the compiletimeness nature and becomes a runtime one.
The details about a constexpr function compile time border: https://www.boost.org/doc/libs/1_65_0/libs/hana/doc/html/index.html#tutorial-appendix-constexpr
For other usage details see the tests.
The entire project currently is experimental.
Adapted from #QuarticCat's answer
template <char...>
struct Str
{
};
#define STRNAME(str) _constexpr_string_type_helper_##str
#define STR(str) \
auto STRNAME(str) = []<size_t... Is>(std::index_sequence<Is...>) \
{ \
constexpr char chars[] = #str; \
return Str<chars[Is]...>{}; \
} \
(std::make_index_sequence<sizeof(#str) - 1>{}); \
decltype(STRNAME(str))
Full code here
Non lambda version, using std::min and sizeof.
Buy the length of string is limited to 256.
This can be used in unevaluated context, such as decltype or sizeof.
I used stamp macros to reduce the code size.
#include <type_traits>
#include <utility>
template <char...>
struct Str
{
};
namespace char_mpl
{
constexpr auto first(char val, char...)
{
return val;
}
constexpr auto second(char, char val, char...)
{
return val;
}
template <class S1, class S2>
struct Concat;
template <char... lefts, char... rights>
struct Concat<Str<lefts...>, Str<rights...>>
{
using type = Str<lefts..., rights...>;
};
template <size_t right_count, class Right>
struct Take;
template <template <char...> class Right, char... vals>
struct Take<0, Right<vals...>>
{
using type = Str<>;
};
template <template <char...> class Right, char... vals>
struct Take<1, Right<vals...>>
{
using type = Str<first(vals...)>;
};
template <template <char...> class Right, char... vals>
struct Take<2, Right<vals...>>
{
using type = Str<first(vals...), second(vals...)>;
};
template <size_t lhs, size_t rhs>
concept greater = lhs > rhs;
// this may be improved for speed.
template <size_t n, char left, char... vals>
requires greater<n, 2> struct Take<n, Str<left, vals...>>
{
using type =
Concat<Str<left>, //
typename Take<n - 1, Str<vals...>>::type//
>::type;
};
};// namespace char_mpl
template <int length, char... vals>
struct RawStr
{
constexpr auto ch(char c, int i)
{
return c;
}
constexpr static auto to_str()
{
return
typename char_mpl::Take<length,
Str<vals...>>::type{};
}
};
#define STAMP4(n, STR, stamper) \
stamper(n, STR) stamper(n + 1, STR) \
stamper(n + 2, STR) stamper(n + 3, STR)
#define STAMP16(n, STR, stamper) \
STAMP4(n, STR, stamper) \
STAMP4(n + 4, STR, stamper) \
STAMP4(n + 8, STR, stamper) \
STAMP4(n + 12, STR, stamper)
#define STAMP64(n, STR, stamper) \
STAMP16(n, STR, stamper) \
STAMP16(n + 16, STR, stamper) \
STAMP16(n + 32, STR, stamper) \
STAMP16(n + 48, STR, stamper)
#define STAMP256(n, STR, stamper) \
STAMP64(n, STR, stamper) \
STAMP64(n + 64, STR, stamper) \
STAMP64(n + 128, STR, stamper) \
STAMP64(n + 192, STR, stamper)
#define STAMP(n, STR, stamper) stamper(STAMP##n, STR, n)
#define CH(STR, i) STR[std::min<size_t>(sizeof(STR) - 1, i)]
#define CSTR_STAMPER_CASE(n, STR) CH(STR, n),
#define CSTR_STAMPER(stamper, STR, n) \
RawStr<sizeof(STR) - 1, \
stamper(0, STR, CSTR_STAMPER_CASE) \
CH(STR, 256)>
#define CSTR(STR) (STAMP(256, STR, CSTR_STAMPER){}).to_str()
int main()
{
constexpr auto s = CSTR("12345");
decltype(CSTR("123123"));
sizeof(CSTR("123123"));
static_assert(
std::is_same_v<
Str<'1'>,
std::remove_cvref_t<decltype(CSTR("1"))>>);
static_assert(
std::is_same_v<
Str<'1', '2'>,
std::remove_cvref_t<decltype(CSTR("12"))>>);
static_assert(
std::is_same_v<
Str<'1', '2', '3', '4', '5'>,
std::remove_cvref_t<decltype(CSTR("12345"))>>);
}
#smilingthax's solution can be shorter by using std::index_sequence:
template<char...>
struct Str {};
template<class T, size_t... Is>
[[nodiscard]] constexpr auto helper(std::index_sequence<Is...>) {
return Str<T{}.chars[Is]...>{};
}
#define STR(str) \
[] { \
struct Temp { \
const char* chars = str; \
}; \
return helper<Temp>(std::make_index_sequence<sizeof(str) - 1>{}); \
}()
or even shorter:
template<char...>
struct Str {};
#define STR(str) \
[]<size_t... Is>(std::index_sequence<Is...>) { \
return Str<str[Is]...>{}; \
} \
(std::make_index_sequence<sizeof(str) - 1>{})
What you are looking for is N3599 Literal operator templates for strings. It was proposed for C++ in 2013 but there was no consensus on the details and it was never added to the standard.
However, GCC and Clang support it as an extension. It lets you split string literals to a template parameter pack of characters:
// some template type to represent a string
template <char... chars>
struct TemplateString {
static constexpr char value[] = { chars... };
template <char... chars2>
constexpr auto operator+(TemplateString<chars2...>) const {
// compile-time concatenation, oh yeah!
return TemplateString<chars..., chars2...>{};
}
};
// a custom user-defined literal called by the compiler when you use your _suffix
template <typename CharType, CharType... chars>
constexpr auto operator""_tstr () {
// since all the chars are constants here, you can do compile-time
// processing with constexpr functions and/or template metaprogramming,
// and then return whatever converted type you like
return TemplateString<chars...>{};
}
// auto = TemplateString<'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'>
constexpr auto str = "Hello"_tstr + " world!"_tstr;
cout << str.value << endl;
As a fallback, the tricks using a macro get you to the same place (as shown in the answer by smilingthax, for example).
Please note that those are the only two ways to accept string literals and split them to constexpr chars: either you use the extension, or you use macro hackery at the call site.