Prepend to static string at compile time - c++

I'm having trouble expanding an array reference. When I pass the array reference to a function template as an argument, the constant nature of the array reference seems to be lost:
#include <cstdlib>
#include <utility>
template<const char ... C>
struct hint_for_opt_cls_holder {
constexpr static const char value[] { '?', C... };
};
template<size_t N, size_t... Is>
static constexpr auto
create_hint_for_opt_cls(const char (&cname)[N],
std::index_sequence<Is...>) {
// fails: cname is not a constant expression
return hint_for_opt_cls_holder<cname[Is]...>::value;
}
template<size_t N>
static constexpr auto
create_hint_for_opt_cls(const char (&cname)[N]) {
constexpr decltype(auto) cname_ = cname; // fails already here, actually
return create_hint_for_opt_cls(cname,
std::make_index_sequence<N>());
}
constexpr static char name[] = "foobar";
constexpr static auto& get_class_name() {
return name;
}
int main() {
// works! knows the return is constant
constexpr decltype(auto) cname = get_class_name();
auto x = create_hint_for_opt_cls(cname);
}

Arguments are not constexpr, you have to turn them in type:
gcc/clang have an extension to allow to build UDL from literal string:
// That template uses the extension
template<typename Char, Char... Cs>
constexpr auto operator"" _cs() -> std::integer_sequence<Char, Cs...> {
return {};
}
See my answer from String-interning at compiletime for profiling to have MAKE_STRING macro if you cannot used the extension (Really more verbose, and hard coded limit for accepted string length).
Then
template<char ... Cs>
static constexpr auto
create_hint_for_opt_cls(std::integer_sequence<char, Cs...>) {
return hint_for_opt_cls_holder<Cs...>::value;
}
constexpr static auto name = "foobar"_cs;

Related

How to create compile-time constant string with prepended length byte?

I have some old code that uses #define to, um, define some string literals, e.g.
#define FredString "\004FRED"
That I would like to update to avoid using #define. Closest I get is something like the following:
static constexpr char* FSraw= "FRED";
static constexpr char FSlen= (char)(sizeof(FSraw) - 1);
static constexpr char* FredString= FSlen FSraw;
but the compiler seems unhappy on the third line.
What would be the best way to construct such a string at compile time? Obviously I could still explicitly encode the length, but also obviously, that's more error prone.
Looking for solutions for C++17 or earlier.
template <std::size_t N>
constexpr std::array<char, N+1> AddLenPrefix(const char (&str)[N])
{
std::array<char, N+1> ret{};
ret[0] = N-1; // Exclude the '\0'.
for (std::size_t i = 0; i < N; i++)
ret[i+1] = str[i];
return ret;
}
static constexpr auto FredString = AddLenPrefix("FRED");
You can also have something like:
#include <string_view>
#include <utility>
template <std::string_view const& S, typename>
struct prepend_length_impl;
template <std::string_view const& S, std::size_t ... Is>
struct prepend_length_impl<S, std::index_sequence<Is...>> {
static constexpr const char value[]{ (sizeof...(Is) + '0'), S[Is]..., 0 };
};
template <std::string_view const& S>
struct prepend_length {
static constexpr std::string_view value =
prepend_length_impl<S, std::make_index_sequence<S.size()>>::value;
};
and then use it like:
static constexpr std::string_view raw = "fred";
static constexpr std::string_view fred = prepend_length<raw>::value; // "4fred"
DEMO

C++11: Initialize constexpr char array with another constexpr char array

I would like to initialize constexpr char[] member with another constexpr char [] member. Is it possible to do in C++11 or above?
#include <iostream>
struct Base {
static constexpr char ValueOne[] = "One";
static constexpr char ValueTwo[] = "Two";
};
template <typename T>
struct ValueOneHolder {
static constexpr char Value[] = T::ValueOne; // << How can one initialize this?
};
int main() {
std::cout << ValueOneHolder<Base>::Value << std::endl;
return 0;
}
I would like to initialize constexpr char[] member with another constexpr char [] member. Is it possible to do in C++11 or above?
Starting from C++14 you can use std::make_index_sequence and std::index_sequence.
If it's OK for you works in a ValueOneHolder specialization, you first can develop a constexpr function that, given a C-style array, return the size of the array
template <typename T, std::size_t N>
constexpr std::size_t getDim (T const (&)[N])
{ return N; }
Nest you can declare ValueOneHolder adding a second template parameter with a default value that is an index sequence corresponding to T::ValueOne
template <typename T,
typename = std::make_index_sequence<getDim(T::ValueOne)>>
struct ValueOneHolder;
and last the easy part: the partial specialization with initialization
template <typename T, std::size_t ... Is>
struct ValueOneHolder<T, std::index_sequence<Is...>>
{ static constexpr char Value[] = { T::ValueOne[Is] ... }; };
Don't forget the following line, outside the struct
template <typename T, std::size_t ... Is>
constexpr char ValueOneHolder<T, std::index_sequence<Is...>>::Value[];
The following is a full C++14 compiling example
#include <utility>
#include <iostream>
struct Base
{
static constexpr char ValueOne[] = "One";
static constexpr char ValueTwo[] = "Two";
};
template <typename T, std::size_t N>
constexpr std::size_t getDim (T const (&)[N])
{ return N; }
template <typename T,
typename = std::make_index_sequence<getDim(T::ValueOne)>>
struct ValueOneHolder;
template <typename T, std::size_t ... Is>
struct ValueOneHolder<T, std::index_sequence<Is...>>
{ static constexpr char Value[] = { T::ValueOne[Is] ... }; };
template <typename T, std::size_t ... Is>
constexpr char ValueOneHolder<T, std::index_sequence<Is...>>::Value[];
int main()
{
std::cout << ValueOneHolder<Base>::Value << std::endl;
}
If you want a C++11, you can develop a substitute for std::make_index_sequence and std::index_sequence.
In this particular example you may declare Value as the following:
template <typename T>
struct ValueOneHolder {
static constexpr auto Value = T::ValueOne; // << How can one initialize this?
};
Please note, GCC will fail to link this example unless you switch to -std=c++17 or add the folloing lines in a source file.
constexpr char Base::ValueOne[];
constexpr char Base::ValueTwo[];
With C++14 it is also possible to make a constexpr copy of a constexpr string (or its substring), as shown in example below:
template<typename CharT, size_t Size>
struct basic_cestring {
using value_type = CharT;
template<size_t... I> constexpr
basic_cestring(const char* str, index_sequence<I...>)
: _data{str[I]...} {}
inline constexpr operator const CharT* () const { return _data; }
const CharT _data[Size + 1];
};
template<size_t Size>
struct cestring : public basic_cestring<char, Size> {
using index = make_index_sequence<Size>;
constexpr cestring(const char* str)
: basic_cestring<char, Size>(str, index{}) {}
};

how to initialize a static constexpr member of std::vector<std::string> in c++11?

I'm trying to initialize a static constexpr std::vector of std::strings inside my class Foo. I will later use the address of its elements.
class Foo {
public:
static constexpr std::vector<std::string> a = {"a", "bc", "232"}; // not working, constexpr variable not literal ....
const std::vector<std::string> a = {"a", "bc", "232"}; // this works
}
using c++11, thanks.
I can live with const instead of constexpr. but it's a little bit odd that there's no way to do this
It's good you can live with const but, just for fun, I show you a way to make a better-than-nothing constexpr static member that uses std::array instead of std::vector and (again) std::array instead of std::string.
Unfortunately you're using C++11, so no std::index_sequence/std::make_index_sequence (available starting from C++14) but I add a C++11 substitute in the following full example.
If you know a superior limit for the length of the strings you want use in the constexpr member, say 9 (3 in you example), you can define a fakeString type as follows
using fakeString = std::array<char, 10u>;
Observe that the size of the std::array is max-length plus one (plus the final zero).
Now you can define foo as follows
struct foo
{
static constexpr std::array<fakeString, 3u> a
{{ fs("a"), fs("bc"), fs("232") }};
};
constexpr std::array<fakeString, 3u> foo::a;
where fs() is a constexpr function that return a fakeString given a C-style array of char and uses a fsh() helper functions
The fs() and fsh() functions are as follows
template <std::size_t ... Is, std::size_t N>
constexpr fakeString fsh (indexSequence<Is...> const &, char const (&s)[N])
{ return {{ s[Is]... }}; }
template <std::size_t N>
constexpr fakeString fs (char const (&s)[N])
{ return fsh(makeIndexSequence<N>{}, s); }
Now you can use foo::a as follows
for ( auto const & fakeS : foo::a )
std::cout << fakeS.data() << std::endl;
Observe that you have to call the data() method that return a char *, that is a C-style string.
I repeat: just for fun.
The following is a full compiling C++11 example
#include <array>
#include <iostream>
template <std::size_t...>
struct indexSequence
{ using type = indexSequence; };
template <typename, typename>
struct concatSequences;
template <std::size_t... S1, std::size_t... S2>
struct concatSequences<indexSequence<S1...>, indexSequence<S2...>>
: public indexSequence<S1..., ( sizeof...(S1) + S2 )...>
{ };
template <std::size_t N>
struct makeIndexSequenceH
: public concatSequences<
typename makeIndexSequenceH<(N>>1)>::type,
typename makeIndexSequenceH<N-(N>>1)>::type>::type
{ };
template<>
struct makeIndexSequenceH<0> : public indexSequence<>
{ };
template<>
struct makeIndexSequenceH<1> : public indexSequence<0>
{ };
template <std::size_t N>
using makeIndexSequence = typename makeIndexSequenceH<N>::type;
using fakeString = std::array<char, 10u>;
template <std::size_t ... Is, std::size_t N>
constexpr fakeString fsh (indexSequence<Is...> const &, char const (&s)[N])
{ return {{ s[Is]... }}; }
template <std::size_t N>
constexpr fakeString fs (char const (&s)[N])
{ return fsh(makeIndexSequence<N>{}, s); }
struct foo
{
static constexpr std::array<fakeString, 3u> a
{{ fs("a"), fs("bc"), fs("232") }};
};
constexpr std::array<fakeString, 3u> foo::a;
int main ()
{
for ( auto const & fakeS : foo::a )
std::cout << fakeS.data() << std::endl;
}

A way to get parameter pack from tuple / array?

So, I'm attempting to mess with constexpr strings as one will do and really only have this thus far:
template<char... CS> struct text {
static constexpr char c_str[] = {CS...};
static constexpr int size = sizeof...(CS);
};
and so this compiles
text<'a','b','c'> t;
std::cout<< t.c_str <<std::endl;
and outputs 'abc' as expected.
What I'm wondering is if there's a non-convoluted way to do the reverse; have a function that returns a text type with the necessary char template arguments given a char array.
Not exactly what you asked... and a little convoluted, I suppose... but if you define a constexpr function to detect the length of a string
constexpr std::size_t strLen (char const * str, std::size_t len = 0U)
{ return *str ? strLen(++str, ++len) : len; }
and an helper struct that define the required type
template <char const *, typename>
struct foo_helper;
template <char const * Str, std::size_t ... Is>
struct foo_helper<Str, std::index_sequence<Is...>>
{ using type = text<Str[Is]...>; };
you can obtain your type passing the string to
template <char const * Str>
struct foo : public foo_helper<Str, std::make_index_sequence<strLen(Str)>>
{ };
Unfortunately you can't pass a string literal to it in this way
foo<"abc">::type
but you have to pass from a global variable
constexpr char abcVar[] = "abc";
and call foo using the global variable
foo<abcVar>::type
This solution uses std::index_sequence and std::make_index_sequence, available only starting from C++14, but isn't too difficult to write a substitute for they in C++11.
The following is a full working example
#include <utility>
#include <iostream>
#include <type_traits>
template <char ... CS>
struct text
{
static constexpr char c_str[] = {CS...};
static constexpr int size = sizeof...(CS);
};
constexpr std::size_t strLen (char const * str, std::size_t len = 0U)
{ return *str ? strLen(++str, ++len) : len; }
template <char const *, typename>
struct foo_helper;
template <char const * Str, std::size_t ... Is>
struct foo_helper<Str, std::index_sequence<Is...>>
{ using type = text<Str[Is]...>; };
template <char const * Str>
struct foo : public foo_helper<Str, std::make_index_sequence<strLen(Str)>>
{ };
constexpr char abcVar[] = "abc";
int main()
{
static_assert(std::is_same<foo<abcVar>::type,
text<'a', 'b', 'c'>>{}, "!");
}
Off Topic: I suggest to add an ending zero in c_str[]
static constexpr char c_str[] = {CS..., 0};
if you want use it as the c_str() method of std::string.

Parameter pack expansion questions

I managed to solve a previous question about initializing a static char array, asked here: Initializing a static char based on template parameter
I don't like the need for a secondary function in my solution:
//static char arr[N] = {[0]='0', [1]='x', [N-1]='\0',};
// ideally want this, but not currently implemented in g++
template <char... chars>
struct zero_str {};
template <unsigned N, char... chars>
struct seq_gen { using type = typename seq_gen<N-1, '0', chars...>::type; };
template <char... chars>
struct seq_gen<0, chars...> { using type = zero_str<chars...>; };
template <size_t N>
struct zero_gen { using type = typename seq_gen<N-1, '0', '\0'>::type; };
template <>
struct zero_gen<0> { using type = zero_str<'\0'>; };
template<size_t N> using strsize = typename zero_gen<N>::type;
template<typename T, char... chars>
const char* n2hexHelper(T val, zero_str<chars...>)
{
thread_local static char hexstr[] = {'0', 'x', chars...};
/* convert to hex */
return hexstr;
};
template<typename T>
const char* n2hex(T val)
{
return n2hexHelper<T> (val, strsize<sizeof(T)*2>() );
}
int main()
{
std::cout << n2hex(1) << std::endl;
return EXIT_SUCCESS;
}
Instead, I'd prefer not to need the dummy variable passed to the helper function, and be able to do something like this:
template<typename T, char... chars>
const char* n2HexIdeal(T val)
{
thread_local static char hexstr[] = {'0', 'x', chars...}; //how to get chars... ?
/* convert to hex */
return hexstr;
}
I have two main questions. 1) is something like my ideal case possible with parameter pack expansions? Or is the only way to force the compiler to deduce my char... is to use it as a function parameter? 2) I'm not very familiar with template metaprogramming, so I was wondering if there are any glaring faults or idiomatic missteps with my above solution.
This is doable in C++14.
template<class=void, std::size_t...Is>
auto index_over( std::index_sequence<Is...> ) {
return [](auto&& f)->decltype(auto) {
return decltype(f)(f)( std::integral_constant<std::size_t, Is>{}... );
};
}
template<std::size_t N>
auto index_over( std::integral_constant< std::size_t, N > ={} ) {
return index_over( std::make_index_sequence<N>{} );
}
These are two helper functions that allow you to expand a bunch of std::size_t compile-time values without a "custom" helper function at each point of use.
We can then use them:
template<typename T>
const char * toStr(T num)
{
thread_local static
auto str = index_over<sizeof(T)*3>()
([&](auto...Is)->std::array<char, 3+3*sizeof(T)> {
return {{ '0', 'x',
(void(Is),'0')...,
'\0'
}};
});
// do something with str
(void)num;
return str.data();
}
to generate and expand our parameter packs inline.
This requires auto variardic lambdas, which is why it doesn't work in C++11.
live example.
If you can accept that your helper function is a static method of a class/struct, you can use the partial specialization as follows
template <typename, typename>
struct n2hexH;
template <typename T, char ... Chs>
struct n2hexH<T, zero_str<Chs...>>
{
static char * func (T const & val)
{
thread_local static char hexstr[] = {'0', 'x', Chs...};
/* convert to hex */
return hexstr;
}
};
Now, your n2hex() function become
template<typename T>
const char* n2hex(T val)
{ return n2hexH<T, strsize<(sizeof(T)<<1U)>>::func(val); }
or you can tranform it in a macro
#define n2hex(X) n2hexH<decltype(X), strsize<(sizeof(X)<<1U)>>::func(X)