2016-01-20 3 views
2

Я работаю над некоторым API для алгоритма, использующего текст.literal charT array

Я хотел бы сделать это НЕ зависимым от типа символа (char, wchar_t ...), поэтому я сделал шаблонные классы с параметром шаблона CharT. Эти классы используют std::basic_string<CharT>.

Мне нужно инициализировать много basic_string со значениями по умолчанию. Если CharT is char Я могу повлиять на литерал «default_text», или если CharT равен wchar_t Я могу повлиять на L «default_text», но это не является общим (это зависит от CharT).

Как вы думаете, каким образом инициализировать basic_string с помощью общего метода?

Если это может быть возможно, мой код находится в C++11.

+1

Вы можете написать вспомогательную функцию со специализациями, которая вернет необходимый литерал. – ForEveR

+0

Зачем вам значение по умолчанию? – Holt

+0

ForEver, я думал об этом решении, но это довольно многословно, так как существует множество значений по умолчанию. – phausy

ответ

2

Поскольку ваш код является общим, я предполагаю, что буквальный текст содержит только символы ASCII. В противном случае вам придется перекодировать его на лету, что будет очень сложно. Чтобы продвигать строковый литерал pure-ASCII типа char[] на другой тип символа, вы можете просто продвигать каждый символ по отдельности.

Если вы собираетесь инициализировать std::basic_string в любом случае, вы также можете это сделать сразу. Следующая функция принимает строковый литерал char[] и тип цели и продвигает его в строку этого типа.

template <typename CharT> 
auto 
as_string(const char *const text) 
{ 
    const auto length = std::strlen(text); 
    auto string = std::basic_string<CharT> {}; 
    string.resize(length); 
    for (auto i = std::size_t {}; i < length; ++i) 
    string[i] = CharT {text[i]}; 
    return string; 
} 

Его можно использовать как этот.

std::cout << as_string<char>("The bats are in the belfry") << '\n'; 
std::wcout << as_string<wchar_t>("The dew is on the moor") << L'\n'; 

Но вы попросили массив символов, а не std::basic_string. В C++ 14, constexpr может многое помочь с этим. Будьте предупреждены, что вам нужны самые последние компиляторы для того, чтобы это было хорошо поддержано.

Первое, что нам нужно сделать, это скопировать нашу собственную версию std::array, которая обеспечивает операции constexpr. Вы можете получить такую ​​же фантазию, как хотите, но я буду держать ее простой здесь.

template <typename T, std::size_t N> 
struct array { T data[N]; }; 

Далее, мы также нуждаемся в версии std::strlenconstexpr.

template <typename CharT> 
constexpr auto 
cstrlen(const CharT *const text) noexcept 
{ 
    auto length = std::size_t {}; 
    for (auto s = text; *s != CharT {0}; ++s) 
    ++length; 
    return length; 
} 

Теперь мы можем написать constexpr функцию, которая способствует нам строковый литерал.

Возможно, было бы удобно обернуть его в макрос. Извини за это.

#define AS_ARRAY(Type, Text) as_array<Type, cstrlen(Text)>(Text).data 

Его можно использовать как этот.

std::cout << AS_ARRAY(char, "The bats are in the belfry") << '\n'; 
std::wcout << AS_ARRAY(wchar_t, "The dew is on the moor") << L'\n'; 
+0

Интересный выбор тестовых строк :-) – AndyG

+0

Спасибо, действительно интересный ответ, я многому научился (я даже не знал, что size_t был определен в std, я всегда использую его без префикса, а мой компилятор не кричит). – phausy

+0

@phausy Определяется в '', который - на большинстве реализаций - перетаскивает в '', а последний имеет 'typedef' в глобальном пространстве имен'. – 5gon12eder