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.
Related
This question already has answers here:
Passing a string literal as a type argument to a class template
(17 answers)
Closed 6 years ago.
I'm trying to find a comfortable way to pass string literals as template arguments. I'm not caring about supporting the widest possible number of compilers, I'm using the latest version of g++ with --std=c++0x.
I've tried a lot of possible solutions but all have disappointed me. I'm sort of giving up, but first I'd like to know why a couple of them failed.
Here they are:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
char const *operator () () const {
return m_sz;
}
};
template<class _rstr>
string const Get() {
return _rstr();
}
int main() {
cout << Get<String("hello")>() << endl;
return 0;
}
And:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
int main() {
String constexpr str = "hello";
cout << Get<str>() << endl;
return 0;
}
The goal was to find a comfortable way to pass a string literal to the useless Get function, which returns its template argument as an std::string object.
EDIT: sorry, maybe my main question isn't clear. My question is: why do those two snippets fail?
You can't use string literals as a template argument, for the
simple reason that it's unspecified whether two instances of a
literal with the same text are the same object or not. In other
words, given:
template <char const* str>
class TC {};
TC< "xyz" > v1;
TC< "xyz" > v2;
It would be unspecified whether v1 and v2 had the same type
or not.
You can use char const[] variables as template arguments,
however, since they have a defined address:
template <char const* str>
class TC {};
extern char const xyz[] = "xyz";
TC< xyz > v1;
TC< xyz > v2;
In this case, v1 and v2 are guaranteed to have the same
type.
EDIT:
I think C++11 removes the need for the extern on the
definition of the string, at least if the string and the
instantiation are all in the same translation unit. I'm not
sure, however; the one time I did something like this, I didn't
have access to C++11.
I know the post is old but I haven't found any solution for this problem here, and maybe someone would be interested in my workaround:
template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
return N - 1;
}
template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};
#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>
// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
Now usage:
template <class SLiteral>
struct usage_of_string_literal {
};
int main() {
usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
Unfortunately one have to provide the length of the string to get it work but it's still more comfortable solution than plain variadic arg template of chars, and the length is verified by the static_assert so the compiler can help to pick appropriate value...
Edit
One more template magic. This one is making use of short-circuit to get rid of the string size from STRING_LITERAL declaration (c++17):
#include <type_traits>
#include <utility>
#define MAX_STRING_LITERAL_LENGTH 11
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s
#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0'))
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0'))
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0'))
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0'))
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0'))
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0'))
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0'))
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0'))
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0'))
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0'))
#define STRING_LITERAL_1(str) str[0]
#define TERMINATED_10(str) TERMINATED_9(str) && str[9]
#define TERMINATED_9(str) TERMINATED_8(str) && str[8]
#define TERMINATED_8(str) TERMINATED_7(str) && str[7]
#define TERMINATED_7(str) TERMINATED_6(str) && str[6]
#define TERMINATED_6(str) TERMINATED_5(str) && str[5]
#define TERMINATED_5(str) TERMINATED_4(str) && str[4]
#define TERMINATED_4(str) TERMINATED_3(str) && str[3]
#define TERMINATED_3(str) TERMINATED_2(str) && str[2]
#define TERMINATED_2(str) TERMINATED_1(str) && str[1]
#define TERMINATED_1(str) str[0]
template <char... Cs>
struct char_pack {
static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0};
static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...);
static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros");
};
template <char... Cs>
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1];
template <char... Cs>
constexpr std::size_t char_pack<Cs...>::non_zero_count;
template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>>
struct string_literal;
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> {
static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'};
};
template <char... Cs, std::size_t... Is>
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1];
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { };
template <const char *>
struct foo {};
int main() {
foo<STRING_LITERAL("abcdefghij")> f;
static_cast<void>(f);
}
[live demo]
You can "simulate" strings with C++11 variadic templates:
template<char... CHARS>
struct string
{
operator const std::string&()
{
static const std::string str{ { CHARS... } };
return str;
}
}
int main()
{
using my_string = string<'h','e','l','l','o',' ','w','o','r','l','d','!','!','!'>;
std::cout << my_string() << std::endl;
}
This prints:
hello world!!!
re: your OP: I'd like to know why a couple of them failed.
The comment by #NatanReed is correct:
Your first snippet fails because Get needs a TYPE and is given an object.
Your second snippet fails because it is illegal to define a template argument as reference to an object.
until C++2003, that is. Then reference to an object became legal.
Template arguments must be constants from a limited set of types.
See: ISO/IEC 14882-2003 §14.1: Template parameters
See: ISO/IEC 14882-2003 §14.3.2: Template non-type arguments
And even then, the String constexpr str = "hello"; must have external linkage. So putting it on the stack inside of main() is not going to work.
Give this a try:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
extern String constexpr globally_visible_str = "hello";
int main() {
cout << Get<globally_visible_str>() << endl;
return 0;
}
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
I am trying to use templates to create an analogue of the type_info::name() function which emits the const-qualified name. E.g. typeid(bool const).name() is "bool" but I want to see "bool const". So for generic types I define:
template<class T> struct type_name { static char const *const _; };
template<class T> char const *const type_name<T>::_ = "type unknown";
char const *const type_name<bool>::_ = "bool";
char const *const type_name<int>::_ = "int";
//etc.
Then type_name<bool>::_ is "bool". For non-const types obviously I could add a separate definition for each type, so char const *const type_name<bool const>::_ = "bool const"; etc. But I thought I would try a partial specialization and a concatenation macro to derive in one line the const-qualified name for any type which has its non-const-qualified name previously defined. So
#define CAT(A, B) A B
template<class T> char const *const type_name<T const>::_
= CAT(type_name<T>::_, " const"); // line [1]
But then type_name<bool const>::_ gives me error C2143: syntax error: missing ';' before 'string' for line [1]. I think that type_name<bool>::_ is a static string known at compile time, so how do I get it concatenated with " const" at compile time?
I tried more simple example but same problem:
char str1[4] = "int";
char *str2 = MYCAT(str1, " const");
I recently revisited this problem, and found that the previous answer I gave produced ridiculously long compile times when concatenating more than a handful of strings.
I have produced a new solution which leverages constexpr functions to remove the recursive templates responsible for the long compilation time.
#include <array>
#include <iostream>
#include <string_view>
template <std::string_view const&... Strs>
struct join
{
// Join all strings into a single std::array of chars
static constexpr auto impl() noexcept
{
constexpr std::size_t len = (Strs.size() + ... + 0);
std::array<char, len + 1> arr{};
auto append = [i = 0, &arr](auto const& s) mutable {
for (auto c : s) arr[i++] = c;
};
(append(Strs), ...);
arr[len] = 0;
return arr;
}
// Give the joined string static storage
static constexpr auto arr = impl();
// View as a std::string_view
static constexpr std::string_view value {arr.data(), arr.size() - 1};
};
// Helper to get the value out
template <std::string_view const&... Strs>
static constexpr auto join_v = join<Strs...>::value;
// Hello world example
static constexpr std::string_view hello = "hello";
static constexpr std::string_view space = " ";
static constexpr std::string_view world = "world";
static constexpr std::string_view bang = "!";
// Join them all together
static constexpr auto joined = join_v<hello, space, world, bang>;
int main()
{
std::cout << joined << '\n';
}
This gives much quicker compile times, even with a large quantity of strings to concatenate.
I personally find this solution easier to follow as the constexpr impl function is akin to how this could be solved at runtime.
Edited with improvements thanks to #Jarod42
EDIT - See my new, improved answer here.
Building on #Hededes answer, if we allow recursive templates, then concatenation of many strings can be implemented as:
#include <string_view>
#include <utility>
#include <iostream>
namespace impl
{
/// Base declaration of our constexpr string_view concatenation helper
template <std::string_view const&, typename, std::string_view const&, typename>
struct concat;
/// Specialisation to yield indices for each char in both provided string_views,
/// allows us flatten them into a single char array
template <std::string_view const& S1,
std::size_t... I1,
std::string_view const& S2,
std::size_t... I2>
struct concat<S1, std::index_sequence<I1...>, S2, std::index_sequence<I2...>>
{
static constexpr const char value[]{S1[I1]..., S2[I2]..., 0};
};
} // namespace impl
/// Base definition for compile time joining of strings
template <std::string_view const&...> struct join;
/// When no strings are given, provide an empty literal
template <>
struct join<>
{
static constexpr std::string_view value = "";
};
/// Base case for recursion where we reach a pair of strings, we concatenate
/// them to produce a new constexpr string
template <std::string_view const& S1, std::string_view const& S2>
struct join<S1, S2>
{
static constexpr std::string_view value =
impl::concat<S1,
std::make_index_sequence<S1.size()>,
S2,
std::make_index_sequence<S2.size()>>::value;
};
/// Main recursive definition for constexpr joining, pass the tail down to our
/// base case specialisation
template <std::string_view const& S, std::string_view const&... Rest>
struct join<S, Rest...>
{
static constexpr std::string_view value =
join<S, join<Rest...>::value>::value;
};
/// Join constexpr string_views to produce another constexpr string_view
template <std::string_view const&... Strs>
static constexpr auto join_v = join<Strs...>::value;
namespace str
{
static constexpr std::string_view a = "Hello ";
static constexpr std::string_view b = "world";
static constexpr std::string_view c = "!";
}
int main()
{
constexpr auto joined = join_v<str::a, str::b, str::c>;
std::cout << joined << '\n';
return 0;
}
I used c++17 with std::string_view as the size method is handy, but this could easily be adapted to use const char[] literals as #Hedede did.
This answer is intended as a response to the title of the question, rather than the more niche problem described.
Suppose I need to call a function foo that takes a const std::string reference from a great number of places in my code:
int foo(const std::string&);
..
foo("bar");
..
foo("baz");
Calling a function with a string literal like this will create temporary std::string objects, copying the literal each time.
Unless I'm mistaken, compilers won't optimize this by creating a static std::string object per literal that can be reused for subsequent calls. I know that g++ has advanced string pool mechanisms, but I don't think it extends to the std::string objects themselves.
I can do this "optimization" myself, which makes the code somewhat less readable:
static std::string bar_string("bar");
foo(bar_string);
..
static std::string baz_string("baz");
foo(baz_string);
Using Callgrind, I can confirm that this does indeed speed up my program.
I thought I'd try to make a macro for this, but I don't know if it's possible. What I would want is something like:
foo(STATIC_STRING("bar"));
..
foo(STATIC_STRING("baz"));
I tried creating a template with the literal as a template parameter, but that proved impossible. And since a function definition in a code block isn't possible, I'm all out of ideas.
Is there an elegant way of doing this, or will I have to resort to the less readable solution?
If that function foo does not make a copy of the string then its interface is sub-optimal. It is better to change it to accept char const* or string_view, so that the caller is not required to construct std::string.
Or add overloads:
void foo(char const* str, size_t str_len); // Does real work.
inline void foo(std::string const& s) { foo(s.data(), s.size()); }
inline void foo(char const* s) { foo(s, strlen(s)); }
You may use something like that to create your static std::string "in place":
#include <cstdint>
#include <string>
// Sequence of char
template <char...Cs> struct char_sequence
{
template <char C> using push_back = char_sequence<Cs..., C>;
};
// Remove all chars from char_sequence from '\0'
template <typename, char...> struct strip_sequence;
template <char...Cs>
struct strip_sequence<char_sequence<>, Cs...>
{
using type = char_sequence<Cs...>;
};
template <char...Cs, char...Cs2>
struct strip_sequence<char_sequence<'\0', Cs...>, Cs2...>
{
using type = char_sequence<Cs2...>;
};
template <char...Cs, char C, char...Cs2>
struct strip_sequence<char_sequence<C, Cs...>, Cs2...>
{
using type = typename strip_sequence<char_sequence<Cs...>, Cs2..., C>::type;
};
// struct to create a std::string
template <typename chars> struct static_string;
template <char...Cs>
struct static_string<char_sequence<Cs...>>
{
static const std::string str;
};
template <char...Cs>
const
std::string static_string<char_sequence<Cs...>>::str = {Cs...};
// helper to get the i_th character (`\0` for out of bound)
template <std::size_t I, std::size_t N>
constexpr char at(const char (&a)[N]) { return I < N ? a[I] : '\0'; }
// helper to check if the c-string will not be truncated
template <std::size_t max_size, std::size_t N>
constexpr bool check_size(const char (&)[N])
{
static_assert(N <= max_size, "string too long");
return N <= max_size;
}
// Helper macros to build char_sequence from c-string
#define PUSH_BACK_8(S, I) \
::push_back<at<(I) + 0>(S)>::push_back<at<(I) + 1>(S)> \
::push_back<at<(I) + 2>(S)>::push_back<at<(I) + 3>(S)> \
::push_back<at<(I) + 4>(S)>::push_back<at<(I) + 5>(S)> \
::push_back<at<(I) + 6>(S)>::push_back<at<(I) + 7>(S)>
#define PUSH_BACK_32(S, I) \
PUSH_BACK_8(S, (I) + 0) PUSH_BACK_8(S, (I) + 8) \
PUSH_BACK_8(S, (I) + 16) PUSH_BACK_8(S, (I) + 24)
#define PUSH_BACK_128(S, I) \
PUSH_BACK_32(S, (I) + 0) PUSH_BACK_32(S, (I) + 32) \
PUSH_BACK_32(S, (I) + 64) PUSH_BACK_32(S, (I) + 96)
// Macro to create char_sequence from c-string (limited to 128 chars) without leading '\0'
#define MAKE_CHAR_SEQUENCE(S) \
strip_sequence<char_sequence<> \
PUSH_BACK_128(S, 0) \
::push_back<check_size<128>(S) ? '\0' : '\0'> \
>::type
// Macro to return an static std::string
#define STATIC_STRING(S) static_string<MAKE_CHAR_SEQUENCE(S)>::str
Live example
gcc has an extension to simplify MAKE_CHAR_SEQUENCE:
template <typename CHAR, CHAR... cs>
constexpr auto operator ""_c() { return char_sequence<cs...>{}; }
If you can use boost 1.55 or greater you can do
#include <boost/utility/string_ref.hpp>
void foo(const boost::string_ref& xyz)
{
}
You could use Boost.Flyweight to make a key-value flyweight from const char* to std::string. I'm not sure about the details, might be that it is enough to use flyweight<std::string> everywhere.
This will work for simple strings - w/o whitespace:
#define DECL_STR(s) const std::string str_##s (#s)
Usage in header (parse once!):
DECL_STR(Foo);
DECL_STR(Bar);
In code:
func(str_Foo);
func(str_Bar);
This question already has answers here:
Passing a string literal as a type argument to a class template
(17 answers)
Closed 6 years ago.
I'm trying to find a comfortable way to pass string literals as template arguments. I'm not caring about supporting the widest possible number of compilers, I'm using the latest version of g++ with --std=c++0x.
I've tried a lot of possible solutions but all have disappointed me. I'm sort of giving up, but first I'd like to know why a couple of them failed.
Here they are:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
char const *operator () () const {
return m_sz;
}
};
template<class _rstr>
string const Get() {
return _rstr();
}
int main() {
cout << Get<String("hello")>() << endl;
return 0;
}
And:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
int main() {
String constexpr str = "hello";
cout << Get<str>() << endl;
return 0;
}
The goal was to find a comfortable way to pass a string literal to the useless Get function, which returns its template argument as an std::string object.
EDIT: sorry, maybe my main question isn't clear. My question is: why do those two snippets fail?
You can't use string literals as a template argument, for the
simple reason that it's unspecified whether two instances of a
literal with the same text are the same object or not. In other
words, given:
template <char const* str>
class TC {};
TC< "xyz" > v1;
TC< "xyz" > v2;
It would be unspecified whether v1 and v2 had the same type
or not.
You can use char const[] variables as template arguments,
however, since they have a defined address:
template <char const* str>
class TC {};
extern char const xyz[] = "xyz";
TC< xyz > v1;
TC< xyz > v2;
In this case, v1 and v2 are guaranteed to have the same
type.
EDIT:
I think C++11 removes the need for the extern on the
definition of the string, at least if the string and the
instantiation are all in the same translation unit. I'm not
sure, however; the one time I did something like this, I didn't
have access to C++11.
I know the post is old but I haven't found any solution for this problem here, and maybe someone would be interested in my workaround:
template <int N>
constexpr int string_literal_length(const char (&str)[N]) {
return N - 1;
}
template <int PassedLength, int CountedLength, char... Characters>
struct string_literal {
static_assert(PassedLength == CountedLength, "Passed to STRING_LITERAL length does not match the length of string...");
};
#define STRING_LITERAL(N, str) string_literal<N, string_literal_length(str), STRING_LITERAL_##N(str)>
// ... as long as we need it ...
#define STRING_LITERAL_128(str) STRING_LITERAL_127(str), str[127]
#define STRING_LITERAL_127(str) STRING_LITERAL_126(str), str[126]
#define STRING_LITERAL_126(str) STRING_LITERAL_125(str), str[125]
#define STRING_LITERAL_125(str) STRING_LITERAL_124(str), str[124]
// ...
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), str[4]
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), str[3]
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), str[2]
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), str[1]
#define STRING_LITERAL_1(str) str[0]
Now usage:
template <class SLiteral>
struct usage_of_string_literal {
};
int main() {
usage_of_string_literal<STRING_LITERAL(12, "123456789012")> uosl;
}
Unfortunately one have to provide the length of the string to get it work but it's still more comfortable solution than plain variadic arg template of chars, and the length is verified by the static_assert so the compiler can help to pick appropriate value...
Edit
One more template magic. This one is making use of short-circuit to get rid of the string size from STRING_LITERAL declaration (c++17):
#include <type_traits>
#include <utility>
#define MAX_STRING_LITERAL_LENGTH 11
#define STRING_LITERAL(str) string_literal<char_pack<STRING_LITERAL_11(str)>>::s
#define STRING_LITERAL_11(str) STRING_LITERAL_10(str), ((TERMINATED_10(str))?(str[10]):('\0'))
#define STRING_LITERAL_10(str) STRING_LITERAL_9(str), ((TERMINATED_9(str))?(str[9]):('\0'))
#define STRING_LITERAL_9(str) STRING_LITERAL_8(str), ((TERMINATED_8(str))?(str[8]):('\0'))
#define STRING_LITERAL_8(str) STRING_LITERAL_7(str), ((TERMINATED_7(str))?(str[7]):('\0'))
#define STRING_LITERAL_7(str) STRING_LITERAL_6(str), ((TERMINATED_6(str))?(str[6]):('\0'))
#define STRING_LITERAL_6(str) STRING_LITERAL_5(str), ((TERMINATED_5(str))?(str[5]):('\0'))
#define STRING_LITERAL_5(str) STRING_LITERAL_4(str), ((TERMINATED_4(str))?(str[4]):('\0'))
#define STRING_LITERAL_4(str) STRING_LITERAL_3(str), ((TERMINATED_3(str))?(str[3]):('\0'))
#define STRING_LITERAL_3(str) STRING_LITERAL_2(str), ((TERMINATED_2(str))?(str[2]):('\0'))
#define STRING_LITERAL_2(str) STRING_LITERAL_1(str), ((TERMINATED_1(str))?(str[1]):('\0'))
#define STRING_LITERAL_1(str) str[0]
#define TERMINATED_10(str) TERMINATED_9(str) && str[9]
#define TERMINATED_9(str) TERMINATED_8(str) && str[8]
#define TERMINATED_8(str) TERMINATED_7(str) && str[7]
#define TERMINATED_7(str) TERMINATED_6(str) && str[6]
#define TERMINATED_6(str) TERMINATED_5(str) && str[5]
#define TERMINATED_5(str) TERMINATED_4(str) && str[4]
#define TERMINATED_4(str) TERMINATED_3(str) && str[3]
#define TERMINATED_3(str) TERMINATED_2(str) && str[2]
#define TERMINATED_2(str) TERMINATED_1(str) && str[1]
#define TERMINATED_1(str) str[0]
template <char... Cs>
struct char_pack {
static constexpr char const arr[sizeof...(Cs) + 1] = {Cs..., 0};
static constexpr std::size_t non_zero_count = (((Cs != 0)?1:0) + ...);
static_assert(non_zero_count < MAX_STRING_LITERAL_LENGTH, "You need to create more macros");
};
template <char... Cs>
constexpr char const char_pack<Cs...>::arr[sizeof...(Cs) + 1];
template <char... Cs>
constexpr std::size_t char_pack<Cs...>::non_zero_count;
template <class CP, class = void, class = std::make_index_sequence<CP::non_zero_count>>
struct string_literal;
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>> {
static constexpr char const s[sizeof...(Cs) + 1] = {Cs..., '\0'};
};
template <char... Cs, std::size_t... Is>
constexpr char const string_literal<char_pack<Cs...>, std::enable_if_t<(Cs && ...)>, std::index_sequence<Is...>>::s[sizeof...(Cs) + 1];
template <char... Cs, std::size_t... Is>
struct string_literal<char_pack<Cs...>, std::enable_if_t<!(Cs && ...)>, std::index_sequence<Is...>>: string_literal<char_pack<char_pack<Cs...>::arr[Is]...>> { };
template <const char *>
struct foo {};
int main() {
foo<STRING_LITERAL("abcdefghij")> f;
static_cast<void>(f);
}
[live demo]
You can "simulate" strings with C++11 variadic templates:
template<char... CHARS>
struct string
{
operator const std::string&()
{
static const std::string str{ { CHARS... } };
return str;
}
}
int main()
{
using my_string = string<'h','e','l','l','o',' ','w','o','r','l','d','!','!','!'>;
std::cout << my_string() << std::endl;
}
This prints:
hello world!!!
re: your OP: I'd like to know why a couple of them failed.
The comment by #NatanReed is correct:
Your first snippet fails because Get needs a TYPE and is given an object.
Your second snippet fails because it is illegal to define a template argument as reference to an object.
until C++2003, that is. Then reference to an object became legal.
Template arguments must be constants from a limited set of types.
See: ISO/IEC 14882-2003 §14.1: Template parameters
See: ISO/IEC 14882-2003 §14.3.2: Template non-type arguments
And even then, the String constexpr str = "hello"; must have external linkage. So putting it on the stack inside of main() is not going to work.
Give this a try:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
extern String constexpr globally_visible_str = "hello";
int main() {
cout << Get<globally_visible_str>() << endl;
return 0;
}