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?How do I expand a tuple into variadic template function's arguments?
"unpacking" a tuple to call a matching function pointer"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{}; \ }()
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{}; \ }()
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{}; \ }()
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; }