Woohoo, I finally did it!!!
(Link to godbold)
#include <iostream>
#include <array>
#include <utility>
#include <string>
#include <string_view>
template <class T>
using const_c_str_char_t = std::remove_const_t<std::remove_pointer_t<T>>;
template <auto str1, auto str2, size_t ...indexes1, size_t ...indexes2>
constexpr decltype(auto) string_append_sequence(std::index_sequence<indexes1...>, std::index_sequence<indexes2...>)
{
using char_type = const_c_str_char_t<decltype(str1())>;
static_assert(std::is_same_v<char_type, const_c_str_char_t<decltype(str2())>>);
return std::integer_sequence<char_type, str1()[indexes1]..., str2()[indexes2]...>{};
}
template <class T, T ...values1, T ...values2>
constexpr decltype(auto) append_sequence(std::integer_sequence<T, values1...>, std::integer_sequence<T, values2...>) {
return std::integer_sequence<T, values1..., values2...>{};
}
template <class sequence_t>
struct string_sequence_to_view;
template <class char_type, char_type ...chars>
struct string_sequence_to_view<std::integer_sequence<char_type, chars...>>
{
using string_view_t = std::conditional_t<std::is_same_v<char_type, char>, std::string_view, std::wstring_view>;
static constexpr decltype(auto) get() {
return string_view_t{c_str};
}
static constexpr const char_type c_str[]{chars..., char_type{}};
};
template <class char_type, size_t value, std::enable_if_t<std::is_same_v<char_type, char> || std::is_same_v<char_type, wchar_t>, int> = 0>
constexpr decltype(auto) integer_to_string_sequence()
{
constexpr auto digits = []()
{
if constexpr (std::is_same_v<char_type, char>) {
return "0123456789abcdefghijklmnopqrstuvwxyz";
}
else if constexpr (std::is_same_v<char_type, wchar_t>) {
return L"0123456789abcdefghijklmnopqrstuvwxyz";
}
};
constexpr size_t remainder = value % 10;
constexpr size_t next_value = value / 10;
if constexpr (next_value != 0) {
return append_sequence(integer_to_string_sequence<char_type, next_value>(), std::integer_sequence<char_type, digits()[remainder]>{});
}
else {
return std::integer_sequence<char_type, digits()[remainder]>{};
}
}
#define INT_TO_C_STR(char_type, num) string_sequence_to_view<decltype(integer_to_string_sequence<char_type, num>())>{}.c_str
#define APPEND_C_STR_AS_VIEW(s1, s2) \
string_sequence_to_view< \
decltype( \
string_append_sequence< \
[] { return s1; }, \
[] { return s2; } \
>( \
std::make_index_sequence<sizeof(s1) / sizeof(s1[0]) - 1>(), \
std::make_index_sequence<sizeof(s2) / sizeof(s1[0]) - 1>() \
) \
) \
>{}.get()
// Number of strings that we want to generate
constexpr size_t NumberOfTextsToGenerate = 20u;
// constexpr function to build a string
template <size_t i>
constexpr std::string_view makeString() {
return APPEND_C_STR_AS_VIEW("test", INT_TO_C_STR(char, i));
}
template <size_t i>
constexpr std::wstring_view makeStringW() {
return APPEND_C_STR_AS_VIEW(L"test", INT_TO_C_STR(wchar_t, i));
}
// Helper: constexpr function that will create an array of string_views and initialize it
template <size_t... ManyIntegers>
constexpr auto generateTextHelper(std::integer_sequence<size_t, ManyIntegers...>) {
return std::array<std::string_view, sizeof...(ManyIntegers)>{ makeString<ManyIntegers>()...};
}
template <size_t... ManyIntegers>
constexpr auto generateTextHelperW(std::integer_sequence<size_t, ManyIntegers...>) {
return std::array<std::wstring_view, sizeof...(ManyIntegers)>{ makeStringW<ManyIntegers>()...};
}
// Helper: constexpr function that will return an array of string_views as shown above with a specified number of texts
constexpr auto generateTextArray() {
return generateTextHelper(std::make_integer_sequence<size_t, NumberOfTextsToGenerate>());
}
constexpr auto generateTextArrayW() {
return generateTextHelperW(std::make_integer_sequence<size_t, NumberOfTextsToGenerate>());
}
// This is a definition of a std::array<std::string_view,UpperBound> initialized with some text
constexpr auto text = generateTextArray();
constexpr auto textW = generateTextArrayW();
int main()
{
for (size_t i{}; i < NumberOfTextsToGenerate; ++i) {
std::cout << text[i] << '\n';
}
for (size_t i{}; i < NumberOfTextsToGenerate; ++i) {
std::wcout << textW[i] << L'\n';
}
return 0;
}
Output:
test0
test1
test2
test3
test4
test5
test6
test7
test8
test9
test10
test11
test12
test13
test14
test15
test16
test17
test18
test19
EDIT: Supported wchar_t string.