I am currently writing some template code where the template parameter is the char type to use. This causes a problem when referring to literal strings. I can, of course, make a struct with the strings I use but I was thinking if it would be possible to make something like:
template<typename chartype, char32_t... chars>
struct tr {
/* some magic here */
};
so that tr<char32_t,U"hello world"> would result in U"hello world"
and tr<char16_t,U"Hello world"> would result in u"hello world"
and tr<char,U"hello world"> would result in "hello world" (in UTF-8).
The magic should of course correctly translate codes above 0x10000 to lead code and follow code for char16_t and to proper 2, 3 and 4 byte codes for UTF-8
at compile time.
Problem is: how do you define a constant C-style string of a given char type using the char32_t... chars template argument? You can extract the characters
from it but how do you rebuild a new string based on the chars of the input string in template code?
Note, the preprocessor can correctly define a string such as "hello world" with suitable prefix u or U if you like but it cannot access the individual characters of the string to properly translate it.
EDIT:
Strings as template arguments are definitely possible in new C++, however,
the template argument is NOT declared as const char * or something like that:
template <char... txt>
struct foo { ... }
allows you to write foo<"hello"> as a type with the string "hello" as template argument. The problem is how to build the string from those characters.
I mean at some point you want the struct to contain a string value to return:
template <char32_t... txt>
struct foo;
template <>
struct foo<> {
static const char16_t * txt() { return ""; }
};
template <char32_t a, char32_t... rest>
struct foo<a, rest...> {
static const char16_t * txt()
{
char16_t buf[100];
int k = 0;
if (a < 0x10000) buf[k++] = a;
else {
buf[k++] = 0xd800 | ((a - 0x10000) >> 10);
buf[k++] = 0xdc00 | ((a-0x10000) & 0x3ff);
}
// copy rest of string into buf + 2..99
u16strcpy(buf + k, foo<rest...>::txt());
return buf;
}
}
Several obvious problems with this "solution", one problem is that buf only have room for 100 characters which will fail if the string is longer. but the main problem is that I wanted this to happen in compile time and this looks very much like run time code to me and is not at all what I wanted to do.
Basically I wanted something that works this way:
foo<char, "hello"> results in something that is effectively a string literal
"hello" or u8"hello".
foo<char16_t, "hello"> results in something that is effectively a string literal u"hello" and foo<char32_t, "hello"> results in something that is effectively a string literal U"hello".
The problem is when writing template code to handle various character formats and then having string literals involved. Yes, you can write a simple struct:
template <typename ChT> struct bar;
template <>
struct bar<char32_t> {
static const char32_t * txta = U"AAAA";
static const char32_t * txtb = U"BBBB";
};
and so on and bar<char16_t> has txta = u"AAAA" etc. Then refer to the strings
in your templated code by bar<T>::txta etc. However, I wish there was a way that you could specify those strings directly in templated code and the compiler would do the right thing. A templated string literal in other words.
Maybe it should be added as a feature to the language that
T<char32_t> string-literal is the same as U string-literal etc
so that you could write
template <typename ChT>
struct foo {
static const ChT * txta = T<ChT> "AAAAA";
};
and the compiler would do the right thing.
This would appear to simply not be legal, even the following is rejected (vs2017, with standard set to latest):
template<char const * ptr>
struct test
{};
void bar()
{
test<"testing"> t;
}
with the error: invalid expression as a template argument for 'ptr', and if that's not going to work trying to convert it at compile-time is a non-starter. And honestly this doesn't seem all that surprising that a pointer-to-data isn't constant enough. to be a template argument.
Here are some tools to make it work in C++17 (might be portable to C++11 and C++14):
static constexpr data member of templated class
The output literal you wish to work with needs some "storage". I suggest to instantiate a unique class template for each literal, e.g., Literal<char, 'f', 'o', 'o', '\0'>. That class can hold the data as astatic constexpr` member.
template<class C, C... cs>
struct Literal {
static_assert(sizeof...(cs) >= 1);
static constexpr C data[] = {cs...};// or use `std::array<C, sizeof...(cs)>`
};
template<class C, C... cs>
constexpr C Literal<C, cs...>::data[];
user-defined string literal to simplify syntax
Of course you wish to avoid typing, e.g., Literal<char, 'f', 'o', 'o', '\0'>. A useful tool to achieve that is the following overload for user-defined string literals.
template<class C, C... cs>
constexpr Literal<C, cs..., C('\0')> operator""_c() {// or use `auto`
return Literal<C, cs..., C('\0')>{};
}
Note how the input literal is passed as non-type template parameters to that overload. That way, it is possible to "carry the value as a type".
constexpr algorithms for re-encoding
So far, you can type "foo"_c to obtain a Literal<char, 'f', 'o', 'o', '\0'> which has a static constexpr data member yielding the same as "foo". Next you can pass that Literal<char, 'f', 'o', 'o', '\0'> to a function which returns a const char16_t(&)[4] to data of the corresponding Literal<char16_t, ..., '\0'>. The syntax could read tr<char16_t>("foo"_c).
The code that transforms a Literal<char, ...> into the corresponding Literal<char16_t, ...> may be based on constexpr algorithms as shown below.
template<
class OutChar, class InChar, InChar... cs,
std::size_t... input_indices, std::size_t... output_indices
>
constexpr auto& tr_impl(// called by `tr` with appropriate `index_sequence`s
Literal<InChar, cs...>,
std::index_sequence<input_indices...>,
std::index_sequence<output_indices...>
) {
constexpr std::size_t outsize = sizeof...(output_indices);
using Buffer = std::array<OutChar, outsize>;
constexpr Buffer buf = encode_as<OutChar, outsize>({cs...});
return Literal<OutChar, buf[output_indices]...>::data;
}
template<class OutChar, class InChar, InChar... cs>
constexpr auto& tr(Literal<InChar, cs...> literal) {
constexpr std::size_t outsize = count_as<OutChar>({cs...});
return tr_impl<OutChar>(
literal,
std::make_index_sequence<sizeof...(cs)>{},// input indices
std::make_index_sequence<outsize>{}// output indices
);
}
The remaining part would be to implement those functions count_as and encode_as.
assign to constexpr auto& in final usage
Finally you can assign to constexpr auto& to verify that type and value are equivalent to the plain string literal based on the desired character type.
static_assert(std::size(U"ππ") == 3);
static_assert(std::size(u"ππ") == 5);
constexpr auto& test = tr<char16_t>(U"ππ"_c);
static_assert(std::is_same<decltype(test), const char16_t(&)[5]>{});
for(std::size_t i=0; i<std::size(u"ππ"); ++i) {
assert(test[i] == u"ππ"[i]);
std::cout << i << ": " << test[i] << std::endl;
}
Related
When I built a function which gives the hexadecimal representation of a nibble (4 bits) and I looked at the binary file, for the lookuptable of the digits, there was an additional 0-char even if it was not used.
const char digits[] = "0123456789abcdef";
I know that you can write it in form of an array:
const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
But that would take a while to write and use more disk-space for other numerical-systems with more digits.
But is there any way to write it as a literal, but without the null-character at the end?
(I am using Clang with -std=c++14)
In C, you could write
const char digits[16] = "0123456789abcdef";
This is actually supported in C as defined in array initialization:
If the size of the array is known, it may be one less than the size of
the string literal, in which case the terminating null character is
ignored: char str[3] = "abc"; // str has type char[3] and holds 'a',
'b', 'c'
For C++, I see no direct way; but one could come around this as follows:
char digits_t[16] = "0123456789abcde";
digits_t[15]='f';
const char* digits = digits_t;
I have no idea why you'd want to do such a thing, but if you can cope with using a compiler extension, Clang and GCC will let you write a templated user-defined literal operator which will chop off the trailing null:
template <typename CharT, std::size_t N>
struct string_literal {
static constexpr std::size_t size = N;
const CharT str[N];
};
template <typename CharT, CharT... Str>
constexpr string_literal<CharT, sizeof...(Str)> operator"" _lit()
{
return {{ Str... }};
}
int main()
{
constexpr auto s = "test"_lit;
static_assert(s.size == 4);
static_assert(s.str[0] == 't'); // etc
}
(Returning a std::array<const char, N> is another option.)
I've no idea whether this is what you're after, but then I don't really understand the motivation to be honest -- even back in the 70s the designers of C weren't too worried about "wasting" a single byte in string literal.
This might be overkill, but if itβs acceptable to use std::array, then you can statically build one from a string literal using constexpr functions:
#include <array>
#include <iostream>
// A type-level list of indices.
template <size_t... Xs>
struct indices { using type = indices<Xs..., sizeof...(Xs)>; };
// Generate indices from 0 to N.
template <std::size_t N>
struct upto { using type = typename upto<N - 1>::type::type; };
template <>
struct upto<0> { using type = indices<>; };
// Make an array by assigning each character
// from the corresponding index in the source.
template <std::size_t... X, typename A = std::array<char, sizeof...(X)>>
constexpr A make_array(char const *const source, const indices<X...>&) {
return A{{source[X]...}};
}
// A convenience function that deduces the size.
template <std::size_t N>
constexpr std::array<char, N - 1> string_constant(char const (&data)[N]) {
return make_array(&data[0], typename upto<N - 1>::type{});
}
int main() {
constexpr auto s = string_constant("123456");
std::cout << sizeof(s) << '\n';
}
Now sizeof(s) is 6, and if you look at the generated assembly, the string literal is stored as .ascii, not .asciz, so there is no trailing null character. You can use the member functions of std::array such as size(), begin(), and end(), and can cast &s[0] to const char * to access character data directly.
I'm working on some API for algorithm involving text.
I would like to make it NOT dependent on the character type (char,wchar_t...), so I have made template classes with a template parameter CharT.
These classes use std::basic_string<CharT>.
I have to initialize a lot of basic_string with default values.
If CharT is char I can affect the literal "default_text", or if CharT is wchar_t I can affect L"default_text", but this is not generic (it is CharT dependant).
Do you think of any way to initialize the basic_string with a generic method ?
If that may help, my code is in C++11.
Since your code is generic, I guess that the literal you have only contains ASCII characters. Otherwise, you'd have to transcode it on the fly which is going to be a lot of hassle. In order to promote a pure-ASCII string literal of type char[] to another character type, you can simply promote each character individually.
If you're going to initialize a std::basic_string anyway, you can as well do it right away. The following function takes a char[] string literal and a target type and promotes it to a string of that type.
template <typename CharT>
auto
as_string(const char *const text)
{
const auto length = std::strlen(text);
auto string = std::basic_string<CharT> {};
string.resize(length);
for (auto i = std::size_t {}; i < length; ++i)
string[i] = CharT {text[i]};
return string;
}
It can be used like this.
std::cout << as_string<char>("The bats are in the belfry") << '\n';
std::wcout << as_string<wchar_t>("The dew is on the moor") << L'\n';
But you've asked for a character array, not a std::basic_string. In C++14, constexpr can help a lot with this. Be warned that you'd need the most recent compilers for this to be supported well.
The first thing we'll have to do is rolling our own version of std::array that provides constexpr operations. You can get as fancy as you want to but I'll keep it simple here.
template <typename T, std::size_t N>
struct array { T data[N]; };
Next, we also need a constexpr version of std::strlen.
template <typename CharT>
constexpr auto
cstrlen(const CharT *const text) noexcept
{
auto length = std::size_t {};
for (auto s = text; *s != CharT {0}; ++s)
++length;
return length;
}
Now we can write a constexpr function that promotes us a string literal.
template <typename CharT, std::size_t Length>
constexpr auto
as_array(const char *const text)
{
auto characters = array<CharT, Length + 1> {};
if (cstrlen(text) != Length)
throw std::invalid_argument {"Don't lie about the length!"};
for (auto i = std::size_t {}; i < Length; ++i)
characters.data[i] = text[i];
characters.data[Length] = CharT {0};
return characters;
}
It might be convenient to wrap it into a macro. I'm sorry for that.
#define AS_ARRAY(Type, Text) as_array<Type, cstrlen(Text)>(Text).data
It can be used like this.
std::cout << AS_ARRAY(char, "The bats are in the belfry") << '\n';
std::wcout << AS_ARRAY(wchar_t, "The dew is on the moor") << L'\n';
I have a number of strings like this:
"343536"_hex
that I would like to convert into their corresponding byte strings. I am using C++11and have defined a user-defined string literals to convert these into hex strings. However, the conversion I currently have cannot be evaluated as a constexpr which is what I'm seeking. In particular I would like to use something like this, but as a constexpr:
std::string operator "" _hex(const char *s, std::size_t slen )
{
std::string str;
str.reserve(slen);
char ch[3];
unsigned long num;
ch[2] = '\0';
for ( ; slen; slen -= 2, s += 2) {
ch[0] = s[0];
ch[1] = s[1];
num = strtoul(ch, NULL, 16);
str.push_back(num);
}
return str;
}
Test driver
int main()
{
std::string src{"653467740035"_hex};
for (const auto &ch : src)
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< (unsigned)ch << '\n';
}
Sample output
65
34
67
74
00
35
The question
To be very, very clear about what I'm asking, it's this:
How can I write a C++11 string literal conversion of this type that can be evaluated at compile time as a constexpr?
In order to achieve what you are trying to do, you will need to have some compile-time string class that is compatible with constexpr. There isn't such a standard thing though. I can see some things that approach it:
boost::mpl::string, but the interface is not really pretty.
boost::log::string_literal, which has the interface you want but lacks the constexpr support.
std::string_literal, which is exactly what you are looking for, but which isn't implemented. It can probably be implementable in C++11 though if you have some free time.
In order to simplify all of this, let's use an overly simplified string_literal class. Note that some of the classes described above have a trailing \0 to be closer to std::string, but we won't bother to add one.
template<std::size_t N>
struct string_literal
{
char data[N];
};
We will also provide operator+ for concatenation. It would take some time to explain how it works and it's not really relevant for the question. Let's say that it is just some template wizardry (std::integer_sequence is a C++14 utility but can be implemented in C++11):
template<std::size_t N1, std::size_t N2, std::size_t... Ind1, std::size_t... Ind2>
constexpr auto concatenate(string_literal<N1> lhs, string_literal<N2> rhs,
std::index_sequence<Ind1...>, std::index_sequence<Ind2...>)
-> string_literal<N1+N2>
{
return { lhs.data[Ind1]... , rhs.data[Ind2]... };
}
template<std::size_t N1, std::size_t N2>
constexpr auto operator+(string_literal<N1> lhs, string_literal<N2> rhs)
-> string_literal<N1+N2>
{
using Indices1 = std::make_index_sequence<N1>;
using Indices2 = std::make_index_sequence<N2>;
return concatenate(lhs, rhs, Indices1{}, Indices2{});
}
You can use the template user-defined literal (with char...) to get rid of the string literal and have a prettier literal (1234_hex instead of "1234"_hex):
template<char... Chars>
auto operator "" _hex()
-> string_literal<sizeof...(Chars)/2>
{
return process<Chars...>();
}
Now, all you need is a function that can process your characters by pairs. A generic one and an overload for the "finish" condition. Note that the enable_if_t is needed to avoid ambiguous function calls (that's C++14, but you can replace it by typename std::enable_if<...>::type in C++11). The "real" work of converting the characters to the equivalent numbers is done in the process overload that only takes two template arguments.
template<char C1, char C2>
constexpr auto process()
-> string_literal<1>
{
return { 16 * (C1 - '0') + (C2 - '0') };
}
template<char C1, char C2, char... Rest,
typename = std::enable_if_t< (sizeof...(Rest) > 0), void >>
constexpr auto process()
-> string_literal<sizeof...(Rest)/2 + 1>
{
return process<C1, C2>() + process<Rest...>();
}
You could add many more checks to ensure that there is always an even number of characters or to ensure that there aren't any bad characters. The code I provided uses some features from the C++14 standard library, but I made sure to only use features that can be easily reimplemented in C++11 if needed. Note that you could probably write a more human-readable program with C++14 thanks to the relaxed restrictions on constexpr functions.
Here is a working C++14 example with all the aforementioned functions and classes. I made sure that your test program still works (I just replaced scr by scr.data in the loop since we use an edulcorated string_literal class).
I've written a variadic template that accepts a variable number of char parameters, i.e.
template <char... Chars>
struct Foo;
I was just wondering if there were any macro tricks that would allow me to instantiate this with syntax similar to the following:
Foo<"abc">
or
Foo<SOME_MACRO("abc")>
or
Foo<SOME_MACRO(abc)>
etc.
Basically, anything that stops you from having to write the characters individually, like so
Foo<'a', 'b', 'c'>
This isn't a big issue for me as it's just for a toy program, but I thought I'd ask anyway.
I've created one today, and tested on GCC4.6.0.
#include <iostream>
#define E(L,I) \
(I < sizeof(L)) ? L[I] : 0
#define STR(X, L) \
typename Expand<X, \
cstring<E(L,0),E(L,1),E(L,2),E(L,3),E(L,4), E(L,5), \
E(L,6),E(L,7),E(L,8),E(L,9),E(L,10), E(L,11), \
E(L,12),E(L,13),E(L,14),E(L,15),E(L,16), E(L,17)> \
cstring<>, sizeof L-1>::type
#define CSTR(L) STR(cstring, L)
template<char ...C> struct cstring { };
template<template<char...> class P, typename S, typename R, int N>
struct Expand;
template<template<char...> class P, char S1, char ...S, char ...R, int N>
struct Expand<P, cstring<S1, S...>, cstring<R...>, N> :
Expand<P, cstring<S...>, cstring<R..., S1>, N-1>{ };
template<template<char...> class P, char S1, char ...S, char ...R>
struct Expand<P, cstring<S1, S...>, cstring<R...>, 0> {
typedef P<R...> type;
};
Some test
template<char ...S>
struct Test {
static void print() {
char x[] = { S... };
std::cout << sizeof...(S) << std::endl;
std::cout << x << std::endl;
}
};
template<char ...C>
void process(cstring<C...>) {
/* process C, possibly at compile time */
}
int main() {
typedef STR(Test, "Hello folks") type;
type::print();
process(CSTR("Hi guys")());
}
So while you don't get a 'a', 'b', 'c', you still get compile time strings.
A solution based on Sylvain Defresne's response above is possible in C++11:
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
template <unsigned int N>
constexpr char get_ch (char const (&s) [N], unsigned int i)
{
return i >= N ? '\0' : s[i];
}
#define STRING_TO_CHARS_EXTRACT(z, n, data) \
BOOST_PP_COMMA_IF(n) get_ch(data, n)
#define STRING_TO_CHARS(STRLEN, STR) \
BOOST_PP_REPEAT(STRLEN, STRING_TO_CHARS_EXTRACT, STR)
// Foo <STRING_TO_CHARS(3, "abc")>
// expands to
// Foo <'a', 'b', 'c'>
Further, provided the template in question is able to handle multiple terminating '\0' characters, we may ease the length requirement in favor of a maximum length:
#define STRING_TO_CHARS_ANY(STR) \
STRING_TO_CHARS(100, STR)
// Foo <STRING_TO_CHARS_ANY("abc")>
// expands to
// Foo <'a', 'b', 'c', '\0', '\0', ...>
The above examples compile properly on clang++ (3.2) and g++ (4.8.0).
There has been a lot of trials, but it is ultimately doomed to fail I think.
To understand why, one needs to understand how the preprocessor works. The input of the preprocessor can be thought of as a stream. This stream is first transformed in preprocessing-tokens (list availabe in The C++ Programming Language, 3rd Edition, Annexe A Grammar, page 795)
On these tokens, the preprocessor may only apply a very restricted number of operations, apart from the digrams/trigrams stuff, this amount to:
file inclusion (for header directives), this may not appear in a macro as far as I know
macro substitution (which is extremely complicated stuff :p)
#: transforms a token into a string-literal token (by surrounding it by quotes)
##: concatenates two tokens
And that's it.
There is no preprocessor instruction that may split a token into several tokens: this is macro substitution, which means actually having a macro defined in the first place
There is no preprocessor instruction to transform a string-literal into a regular token (removing the quotes) that could then be subject to macro substitution.
I therefore hold the claim that it is impossible (either in C++03 or C++0x), though there might (possibly) be compiler specific extensions for this.
Based on user1653543's solution above.
Some template magic:
template <unsigned int N>
constexpr char getch (char const (&s) [N], unsigned int i)
{
return i >= N ? '\0' : s[i];
}
template<char ... Cs>
struct split_helper;
template<char C, char ... Cs>
struct split_helper<C, Cs...>
{
typedef push_front_t<typename split_helper<Cs...>::type, char_<C>> type;
};
template<char ... Cs>
struct split_helper<'\0', Cs...>
{
typedef std::integer_sequence<char> type;
};
template<char ... Cs>
using split_helper_t = typename split_helper<Cs...>::type;
Some PP magic:
#define SPLIT_CHARS_EXTRACT(z, n, data) \
BOOST_PP_COMMA_IF(n) getch(data, n)
#define STRING_N(n, str) \
split_helper_t<BOOST_PP_REPEAT(n, SPLIT_CHARS_EXTRACT, str)>
#define STRING(str) STRING_N(BOOST_PP_LIMIT_REPEAT, str)
split_helper just helper to cut trailing zeroes. Now STRING("Hello") is a typed compile-time char sequence (std::integer_sequence<char, 'H', 'e', 'l', 'l', 'o'>). Length of string constants is up to BOOST_PP_LIMIT_REPEAT characters.
Homework: implement push_front_t and c_str to get null-terminated string of std::integer_sequence<char, ...>. (Although, you can try to use Boost.MPL)
this used to work in an early version of msvc, I don't know if it still does:
#define CHAR_SPLIT(...) ##__VA_ARGS__
Unfortunately, I believe this cannot be done. The best you can get from the preprocessor is provided by Boost.Preprocessor, most notably through its data types :
array : syntax would be (3, (a, b, c))
list : syntax would be (a, (b, (c, BOOST_PP_NIL)))
sequence : syntax would be (a)(b)(c)
tuple : syntax would be (a, b, c)
From any of these types, you can easily create a macro which would build a comma separated list of single-quote enclosed items (see for example BOOST_PP_SEQ_ENUM), but I believe the input of this macro will have to be one of these types, and all require the characters to be typed individually.
Based on what I was discussing above, the following awful template hackery may be sufficient to pull this off. I haven't tested this (sorry!), but I'm pretty sure it or something close to it might work.
The first step is to build a template class that just holds a tuple of chars:
template <char... Chars> class CharTuple {};
Now, let's build an adapter that can transform a C-style string into a CharTuple. To do this, we'll need the following helper class which is essentially a LISP-style cons for tuples:
template <typename Tuple, char ch> class Cons;
template <char... Chars, char ch> class Cons<CharTuple<Chars... ch>> {
typedef CharTuple<ch, Chars...> type;
}
Let's also assume we have a meta-if statement:
template <bool Condition, typename TrueType, typename FalseType> class If {
typedef typename TrueType::type type;
};
template <typename TrueType, typename FalseType> class If<False> {
typedef typename FalseType::type type;
};
Then the following should let you convert a C-style string into a tuple:
template <typename T> class Identity {
typedef T type;
};
template <char* str> class StringToChars {
typedef typename If<*str == '\0', Identity<CharTuple<>>,
Cons<*str, typename StringToChars<str + 1>::type>>::type type;
};
Now that you can convert a C-style string into a tuple of chars, you can funnel your input string through this type to recover the tuple. We'll need to do a bit more machinery to get this working, though. Isn't TMP fun? :-)
The first step is to take your original code:
template <char... Chars> class Foo { /* ... */ };
and use some template specialization to convert it to
template <typename> class FooImpl;
tempalte <char... Chars> class FooImpl<CharTuple<Chars...>> { /* ... */ };
It's just another layer of indirection; nothing more.
Finally, you should be able to do this:
template <char* str> class Foo {
typedef typename FooImpl<typename StringToChars<str>::type>::type type;
};
I really hope this works. If it doesn't, I still think this is worth posting because it's probably Ξ΅-close to a valid answer. :-)
In C++14, this can be done by using an immediately invoked lambda and a static member function, similar to BOOST_HANA_STRING:
#include <utility>
template <char... Cs>
struct my_string {};
template <typename T, std::size_t... Is>
constexpr auto as_chars_impl(std::index_sequence<Is...>) {
return my_string<T::str()[Is]...>{};
}
template <typename T>
constexpr auto as_chars() {
return as_chars_impl<T>(
std::make_index_sequence<sizeof(T::str())-1>{});
}
#define STR(literal) \
[]{ \
struct literal_to_chars { \
static constexpr decltype(auto) str() { \
return literal; \
} \
}; \
return as_chars<literal_to_chars>(); \
}()
Live on Godbolt
Before C++17, the object returned by STR("some literal") can't be constexpr because the lambda can't be constexpr.
Before C++20, you can't just write decltype(STR("some literal")) because lambdas are not allowed in unevaluated contexts.
This question already has answers here:
Passing a string literal as a type argument to a class template
(17 answers)
Closed 6 years ago.
Can C-Style strings be used as template arguments?
I tried:
template <char *str>
struct X
{
const char *GetString() const
{
return str;
}
};
int main()
{
X<"String"> x;
cout<<x.GetString();
}
And although I get no complaints about the class definition, the instantiation yields 'X' : invalid expression as a template argument for 'str' (VC).
A string literal cannot be used as a template argument.
Update: Nowadays, a few years after this question was asked and answered, it is possible to use string literals as template arguments. With C++11, we can use characters packs as template arguments (template<char ...c>) and it is possible to pass a literal string to such a template.
This would work, however:
template <char const *str>
struct X
{
const char *GetString() const
{
return str;
}
};
char global_string[] = "String";
int main()
{
X<global_string> x;
cout<<x.GetString();
}
Sorry to post on such an old question, but here's what I feel is the cleanest approach to actually pass a literal as the argument without using storage.
Encode the string as a type:
template <char... chars>
using tstring = std::integer_sequence<char, chars...>;
Create a user defined literal operator:
template <typename T, T... chars>
constexpr tstring<chars...> operator""_tstr() { return { }; }
And use partial specialization to recover the character data as needed:
template <typename>
struct X;
template <char... elements>
struct X<tstring<elements...>> {
const char* GetString() const
{
static constexpr char str[sizeof...(elements) + 1] = { elements..., '\0' };
return str;
}
};
This allows you to write:
X<decltype("my_string"_tstr)>
The user defined literal uses non-standard (n3599) functionality not in C++14 but that is supported by recent GCC and Clang builds, and hopefully will be reconsidered for C++1z.
I known, this topic is a bit old but I put this comment if anyone is interested. I achieved templates with passing literal string as argument with combination of MACROS.
I made a code example,
#include <stdio.h>
#include <iostream>
#include <vector>
#include <memory>
#include <string.h>
using namespace std;
#define MAX_CONST_CHAR 100
#define MIN(a,b) (a)<(b)?(a):(b)
#define _T(s)\
getChr(s,0),\
getChr(s,1),\
getChr(s,2),\
getChr(s,3),\
getChr(s,4),\
getChr(s,5),\
getChr(s,6),\
getChr(s,7),\
getChr(s,8),\
getChr(s,9),\
getChr(s,10),\
getChr(s,11),\
getChr(s,12),\
getChr(s,13),\
getChr(s,14),\
getChr(s,15),\
getChr(s,16),\
getChr(s,17),\
getChr(s,18),\
getChr(s,19),\
getChr(s,20),\
getChr(s,21),\
getChr(s,22),\
getChr(s,23),\
getChr(s,24),\
getChr(s,25),\
getChr(s,26),\
getChr(s,27),\
getChr(s,28),\
getChr(s,29),\
getChr(s,30),\
getChr(s,31),\
getChr(s,32),\
getChr(s,33),\
getChr(s,34),\
getChr(s,35),\
getChr(s,36),\
getChr(s,37),\
getChr(s,38),\
getChr(s,39),\
getChr(s,40),\
getChr(s,41),\
getChr(s,42),\
getChr(s,43),\
getChr(s,44),\
getChr(s,45),\
getChr(s,46),\
getChr(s,47),\
getChr(s,48),\
getChr(s,49),\
getChr(s,50),\
getChr(s,51),\
getChr(s,52),\
getChr(s,53),\
getChr(s,54),\
getChr(s,55),\
getChr(s,56),\
getChr(s,57),\
getChr(s,58),\
getChr(s,59),\
getChr(s,60),\
getChr(s,61),\
getChr(s,62),\
getChr(s,63),\
getChr(s,64),\
getChr(s,65),\
getChr(s,66),\
getChr(s,67),\
getChr(s,68),\
getChr(s,69),\
getChr(s,70),\
getChr(s,71),\
getChr(s,72),\
getChr(s,73),\
getChr(s,74),\
getChr(s,75),\
getChr(s,76),\
getChr(s,77),\
getChr(s,78),\
getChr(s,79),\
getChr(s,80),\
getChr(s,81),\
getChr(s,82),\
getChr(s,83),\
getChr(s,84),\
getChr(s,85),\
getChr(s,86),\
getChr(s,87),\
getChr(s,88),\
getChr(s,89),\
getChr(s,90),\
getChr(s,91),\
getChr(s,92),\
getChr(s,93),\
getChr(s,94),\
getChr(s,95),\
getChr(s,96),\
getChr(s,97),\
getChr(s,98),\
getChr(s,99),\
getChr(s,100)
#define getChr(name, ii) ((MIN(ii,MAX_CONST_CHAR))<sizeof(name)/sizeof(*name)?name[ii]:0)
template <char... Chars_>
class E {
public:
string *str;
E(){
std::vector<char> vec = {Chars_...};
str = new string(vec.begin(),vec.end());
}
~E()
{
delete str;
}
};
int main(int argc, char *argv[])
{
E<_T("Any template can pass const strings literals")> e;
printf("%s",e.str->c_str());
}
This works with g++ 4.6 and passing argument -std=c++0x, and have a limit of 100 char but, of course, can be as greater as you want. Maybe this technique is not well optimized, but it will be more productive than declare the needed external variables (I'm sure ;) )
Constraints: The literal string must be one and last argument of the template due the passing of variadics arguments.
EDIT: Thanks to Padek he tested that this piece of code also it works with Visual Studio 2017 but changing strlen by sizeof(name)/sizeof(*name).
No, you can't work with string literals at compile time. The best you can get are the weird multicharacter literals (e.g. 'abcd') which some compile-time parsers use. They are mentioned in Β§2.13.2.1:
An ordinary character literal that
contains more than one c-char is a
multicharacter literal. A multicharac-
ter literal has type int and
implementation-defined value.
In C++0x there might be ways around this limitations though with the new string literals, Arctic Interactive has an interesting article on that.
With C++11 you can fairly sanely represent string literals as variadic template arguments, i.e. a collection of int template parameters. I've put together a proof of concept example that sets up one such template without manually having to write foo<16, 73, 51 ...> for every such string.
Example:
// The template we want to pass a string to
template <int... Args>
struct foo {
// It needs one helper function for decltype magic, this could be avoided though
template <int N>
static foo<N, Args...> add_one();
};
// This is the string we want to use with foo, simulating foo<"Hello world!" __FILE__>:
constexpr const char *teststr = "Hello world!" __FILE__;
// Get char N of a string literal
constexpr int strchr(const char *str, int N) { return str[N]; }
// recursive helper to build the typedef from teststr
template <int N, int P=0>
struct builder {
typedef typename builder<N, P+1>::type child;
typedef decltype(child::template add_one<strchr(teststr,P)>()) type;
};
template <int N>
struct builder<N,N> {
typedef foo<strchr(teststr, N)> type;
};
// compile time strlen
constexpr int slen(const char *str) {
return *str ? 1 + slen(str+1) : 0;
}
int main() {
builder<slen(teststr)>::type test;
// compile error to force the type to be printed:
int foo = test;
}
You'll need at least gcc 4.6 for constexpr and it could use some polish still but the compiler error I get indicates the type is being built sanely:
error: cannot convert βbuilder<19>::type {aka foo<72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 115, 108, 105, 116, 46, 99, 99, 0>}β to βintβ in initializatio
No. According to C++ Standard 14.3.2/1:
A template-argument for a non-type, non-template template-parameter shall be one of:
β an integral constant-expression of integral or enumeration type; or
β the name of a non-type template-parameter; or
β the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference;or
β a pointer to member expressed as described in 5.3.1 .
Strings are not in the list.
You can use address of string with external linkage as a template parameter, e.g.:
template <const char** T> class My {
public:
void do_stuff() {
std::cout << "zzz";
}
};
const char* str;
int main()
{
My<&str> zz;
zz.do_stuff();
printf("Result: %d %d \n", 60 % 10 + 1, (60 % 10 ) + 1 );
}
C++ does not know about strings. It only knowns about "arrays of characters" and there the literal would be the pointer to the array. So if you would use the "value" of your string as template parameter you would actually use the pointer value.