Преобразовать `hana::string` в`constexpr const char (&)[]`
У меня есть старый код, который использует что-то очень похожее на str_const
описано здесь и здесь, чтобы сделать некоторые манипуляции строк constexpr. str_const
литеральный тип, описанный Скоттом Шурром, который может быть построен из строкового литерала, потому что он имеет конструктор шаблона из const char (&)[]
,
Теперь у меня есть новый код, использующий boost::hana
,
Я хотел бы иметь возможность взять hana::string
и создать str_const
это относится к этому. Самый простой способ сделать это - преобразовать hana::string
к constexpr const char (&)[]
, (На самом деле, на данный момент это не самый простой способ, самый простой способ, конечно, это добавить новый конструктор шаблона в мой str_const
реализация. Но на данный момент вопрос приобрел собственную жизнь, и я в основном заинтересован в том, можно ли это сделать с hana::string
, Итак, давайте предположим, что мне не разрешено менять str_const
реализация.)
Однако в hana
документы способ конвертировать hana::string
к строке времени выполнения hana::to<const char *>
,
Оптимистично, я пробовал различные формы hana::to<const char (&)[hana::length(...)]> (...)
но это вызывает статические утверждения в hana
терпеть неудачу.
Другой вариант, предложенный hana
документы использовать hana::unpack
а затем вставьте символы в массив самостоятельно. Я написал этот код
template <typename T, size_t N>
struct array {
T arr[N];
};
struct char_packer {
template <typename... Ts>
constexpr auto operator()(Ts... ts) -> array<const char, sizeof...(ts) + 1> {
return array<const char, sizeof...(ts) + 1>{{ ts... , 0 }};
}
};
template <typename S>
struct string_keeper {
static constexpr auto my_array = hana::unpack(S{}, char_packer{});
};
template <int N>
using char_arr = const char [N];
template <typename S>
constexpr auto to_string_literal(S &&) -> const char_arr<decltype(hana::length(S{}))::value + 1> & {
return string_keeper<S>::my_array.arr;
}
Я думаю, что это почти работает, по крайней мере, компилируется. Но если ссылки также используются во время выполнения, то происходит сбой с ошибкой компоновщика: undefined reference to ... string_keeper<boost::hana::string<(char)97> >::my_array
,
(На самом деле, я думаю, что понимаю, почему это проблема с ODR, и если я подумаю над этим немного дольше, я могу вспомнить, как это исправить... не уверен...)
Интуитивно я чувствую, что должен быть способ сделать это. Так как, hana
уже позволяет мне конвертировать hana::string
в constexpr const char *
где указатель указывает на массив, который я хочу. На самом деле это даже наводит на мысль о том, что может быть злой вариант, когда я пытаюсь const char *
вернуться к (&)[]
тип, хотя это также кажется, что это потребует делать вещи, которые не будут разрешены в constexpr
функции. В любом случае, если hana
может сделать этот массив, то, конечно, я тоже могу, или как-то убедить его дать мне более точно.
Есть ли способ исправить мой код выше? Есть ли более простой способ сделать это в течение hana
что я упустил из виду? Это действительно невозможно по какой-то причине?
1 ответ
Еще одна проблема заключается в том, что при возврате из функции необработанный массив символов будет преобразован в указатель. Я бы предложил построить str_const
объект в контексте вашей функции, которая, я считаю, выполняет ваше намерение создать str_const
без изменения его интерфейса.
В следующем примере используется шаблон переменной верхнего уровня для создания массива, который hana::string
реализация использует:
#define BOOST_HANA_CONFIG_ENABLE_STRING_UDL
#include <boost/hana.hpp>
#include <stdexcept>
namespace hana = boost::hana;
using namespace hana::literals;
class str_const {
const char * const p_;
const std::size_t sz_;
public:
template <std::size_t N>
constexpr str_const( const char( & a )[ N ] )
: p_( a ), sz_( N - 1 ) {}
constexpr char operator[]( std::size_t n ) const {
return n < sz_ ? p_[ n ] : throw std::out_of_range( "" );
}
constexpr std::size_t size() const { return sz_; }
};
template <char ...c>
constexpr char string_storage[sizeof...(c) + 1] = {c..., '\0'};
struct to_str_const_helper {
template <typename ...Ts>
constexpr auto operator()(Ts...) {
return str_const(string_storage<Ts::value...>);
}
};
template <typename S>
constexpr auto to_str_const(S) {
return hana::unpack(S{}, to_str_const_helper{});
}
int main()
{
constexpr str_const str = to_str_const("foo"_s);
static_assert(str[0] == 'f', "");
static_assert(str[1] == 'o', "");
static_assert(str[2] == 'o', "");
}