5

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;
}
2
  • Use std::array instead? Commented Jan 26, 2019 at 20:24
  • Another option might be a constexpr reference, unless you need unique addresses for the two arrays. Commented Jan 26, 2019 at 20:27

2 Answers 2

2

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 following 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{}) {}
};
Sign up to request clarification or add additional context in comments.

Comments

2

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.

2 Comments

I doubt one can make a substitute for index_sequence - it i based on a magic internal feature
@hutorny - a substitute for std::index_sequence is trivial; it's a substitute for std::make_index_sequence (or better: for std::make_integer_sequence) that is more complicated; but not so much. The real problem is that std::make_integer_sequence should (the standard say) be a std::integer_sequence, not only something that inherit from it. And this I don't know how to make in C++11 (but this problem require only a little change in ValueOneHolders code)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.