C ++ 11: Инициализировать массив символов constexpr с другим массивом символов constexpr - PullRequest
0 голосов
/ 26 января 2019

Я хотел бы инициализировать constexpr char[] член с другим constexpr char [] членом.Можно ли это сделать в C++11 или выше?

#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 ]

0 голосов
/ 26 января 2019

В этом конкретном примере вы можете объявить Value следующим образом:

template <typename T>
struct ValueOneHolder {
  static constexpr auto Value = T::ValueOne; // << How can one initialize this?
};

Обратите внимание, что GCC не сможет связать этот пример, если вы не переключитесь на -std = c ++ 17 или не добавите следующие строкив исходном файле.

constexpr char Base::ValueOne[];
constexpr char Base::ValueTwo[];

С C ++ 14 также можно сделать копию constexpr строки constexpr (или ее подстроки), как показано в примере ниже:

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{}) {}
};
0 голосов
/ 26 января 2019

Я хотел бы инициализировать constexpr char[] элемент с другим constexpr char [] членом. Можно ли это сделать в C++11 или выше?

Начиная с C ++ 14 вы можете использовать std::make_index_sequence и std::index_sequence.

Если все в порядке, если вы работаете со специализацией ValueOneHolder, сначала вы можете разработать функцию constexpr, которая при наличии массива в стиле C возвращает размер массива

template <typename T, std::size_t N>
constexpr std::size_t getDim (T const (&)[N])
 { return N; }

Гнездо, которое вы можете объявить ValueOneHolder добавив второй параметр шаблона со значением по умолчанию, которое является последовательностью индекса, соответствующей T::ValueOne

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[];

Ниже приведен полный пример компиляции C ++ 14

#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;
 }

Если вы хотите C ++ 11, вы можете разработать замену std::make_index_sequence и std::index_sequence.

...