Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 754
TMS Avatar asked Jul 13 '26 08:07

TMS


1 Answers

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;
 }
like image 125
max66 Avatar answered Jul 16 '26 02:07

max66