C++ 如何在编译时用一系列字符串视图创建constepr数组?

C++ 如何在编译时用一系列字符串视图创建constepr数组?,c++,arrays,templates,constexpr,string-view,C++,Arrays,Templates,Constexpr,String View,我想创建一个constexpr std::array。例如,它应该包含constepr std::strings\u视图的,如下所示: “text0”、“text1”、“text2”。。。。。“textn” 我提出了以下初步解决方案: #include <iostream> #include <array> #include <utility> #include <string> #include <string_view> // N

我想创建一个
constexpr std::array
。例如,它应该包含
constepr std::strings\u视图的
,如下所示:

“text0”、“text1”、“text2”。。。。。“textn”

我提出了以下初步解决方案:

#include <iostream>
#include <array>
#include <utility>
#include <string>
#include <string_view>

// Number of strings that we want to generate
constexpr size_t NumberOfTextsToGenerate = 10u;

// constexpr function to build a string
constexpr std::string_view makeString(unsigned int i) {
    return std::string_view("text");
}

// Helper: constexpr function that will create an array of string_views and initialize it
template <unsigned int... ManyIntegers>
constexpr auto generateTextHelper(std::integer_sequence<unsigned int, ManyIntegers...>) {
    return std::array<std::string_view, sizeof...(ManyIntegers)>{ {makeString(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<unsigned int, NumberOfTextsToGenerate>());
}

// This is a definition of a std::array<std::string_view,UpperBound> initialized with some text
constexpr auto text = generateTextArray();

int main() {
    for (size_t i{}; i < NumberOfTextsToGenerate; ++i)
        std::cout << text[i] << '\n';
    return 0;
}
#包括
#包括
#包括
#包括
#包括
//要生成的字符串数
constexpr size\u t NumberOfTextsToGenerate=10u;
//constexpr函数生成字符串
constexpr std::string\u视图makeString(unsigned int i){
返回std::string_视图(“文本”);
}
//Helper:constexpr函数,它将创建一个字符串视图数组并对其进行初始化
模板
constexpr自动生成exthelper(std::integer_序列){
返回std::数组{{makeString(ManyIntegers)…};
}
//Helper:constexpr函数,它将返回一个字符串视图数组,如上图所示,带有指定数量的文本
constexpr自动生成extarray(){
返回generateTextHelper(std::make_integer_sequence());
}
//这是用一些文本初始化的std::数组的定义
constexpr auto text=generateTextArray();
int main(){
for(size_t i{};istd::cout您可以执行以下操作:

constexpr size\u t NumberOfTextsToGenerate=10u;
模板
结构数字\u到\u结束\u impl{
静态constexpr const char值[]{'t','e','x','t',(I+'0'),0};
};
模板
结构数字\u到\u结尾{
静态constexpr std::string\u view value=数字\u到\u end\u impl::value;
};
模板
constexpr std::string\u视图makeString(){
将数字_返回到_end::value;
}
模板
constexpr自动生成exthelper(std::integer_序列){
返回std::数组{{makeString()…}};
}
// ...
看看这本书

但是,当
要生成的文本数超过10时,这将不起作用。

通过STL更新

下面的解决方案是通过boost的预处理宏实现的


嗯,我花了三个小时,但我仍然无法通过STL成功地完成,所以我放弃了,最终我回到了

如果不想导入整个boost库,可以将这些
boost\u PP
宏分离到项目中,尽管它们仍然非常大,因此可能需要花费一些时间

以下是代码(链接到):


呜呼,我终于做到了

(链接至)



编辑:支持
wchar\t
string。

我现在找到了一个最终满足我需求的解决方案

因为SO用户提供了很多很好的答案,并且对我的问题有了更多的回答

我现在将使用以下代码

#include <iostream>
#include <algorithm>
#include <iterator>
#include <array>
#include <string>

// Specification for the output that we want to generate
constexpr const char BaseString[]{ "text" };    // Some example text
constexpr size_t StartIndex = 1u;               // Start index. So first array element will be "Text1"
constexpr size_t NumberOfElements = 20u;        // Number of elements to create. Last array element will be "Text20"

// These templates are used to generate a std::array
namespace ConstexprGenerator {
    // To create something like "text123" as constexpr
    template <const size_t numberToConvert, const char* Text>
    class Converter {
    public:
        // Some helper variables for calculating sizes
        static constexpr size_t TextLength{ std::char_traits<char>::length(Text) };
        static constexpr size_t NumberOfDigits{ ([]() constexpr noexcept {size_t result = 0; int temp = numberToConvert; for (; temp != 0; temp /= 10) ++result; return result; }()) };
        static constexpr size_t ArrayLength{ (numberToConvert ? 1u : 2u) + NumberOfDigits + TextLength };

        // Here we will store the string
        std::array<char, ArrayLength> internalString{};

        // Constructor: Copy text and Convert number to character digits
        constexpr Converter() noexcept {
            size_t i{ 0 };  for (; i < TextLength; ++i) internalString[i] = Text[i]; // Copy text
            if (numberToConvert == 0) internalString[i] = '0';  // In case that the given number is 0, then simply copy '0' character   
            else {
                i = NumberOfDigits + TextLength - 1;            // Convert number to character digits
                int number = numberToConvert; for (; number; number /= 10)
                    internalString[i--] = number % 10 + '0';
            }
        }
        constexpr std::array<char, ArrayLength> get() const { return *this; };              // getter
        constexpr operator std::array<char, ArrayLength>() const { return internalString; } // type cast
    };

    // Templated variable. Will have always a different type, depending on the template parameters
    template<const size_t numberToConvert, const char* Text>
    constexpr auto Converted = Converter<numberToConvert, Text>{}.get();

    // Generate a std::array with n elements that consist of const char *, pointing to Textx...Texty
    template <int... ManyIntegers>
    constexpr auto generateTextHelper(std::integer_sequence<size_t, ManyIntegers...>) noexcept {
        return std::array<const char*, sizeof...(ManyIntegers)>{ {Converted<ManyIntegers + StartIndex, BaseString>.data()...}};
    }
    // Generate the required number of texts
    constexpr auto generateTextArray()noexcept {
        return generateTextHelper(std::make_integer_sequence<size_t, NumberOfElements>());
    }
}
// This is a constexpr array
constexpr auto text = ConstexprGenerator::generateTextArray();

int main() {
    std::copy(text.begin(), text.end(), std::ostream_iterator<const char*>(std::cout, "\n"));
    return 0;
}
#包括
#包括
#包括
#包括
#包括
//我们要生成的输出的规范
constexpr const char BaseString[]{“text”};//一些示例文本
constexpr size\u t StartIndex=1u;//开始索引。所以第一个数组元素将是“Text1”
constexpr size\u t NumberOfElements=20u;//要创建的元素数。最后一个数组元素将是“Text20”
//这些模板用于生成std::数组
命名空间constexpergenerator{
//创建类似“text123”的内容作为constexpr
模板
类转换器{
公众:
//用于计算尺寸的一些辅助变量
静态constexpr size\u t TextLength{std::char\u traits::length(Text)};
静态constexpr size_t NumberOfDigits{([])constexpr noexcept{size_t result=0;int temp=numberToConvert;for(;temp!=0;temp/=10)+result;返回结果;}())};
静态constexpr size_t arraylelength{(numberToConvert?1u:2u)+NumberOfDigits+textllength};
//这里我们将存储字符串
std::数组内部字符串{};
//构造函数:复制文本并将数字转换为字符数字
constexpr Converter()无异常{
size_t i{0};for(;i=数字%10+'0';
}
}
constexpr std::array get()const{return*this;};//getter
constexpr运算符std::array()const{return internalString;}//类型转换
};
//模板化变量。将始终具有不同的类型,具体取决于模板参数
模板
constexpr auto Converted=转换器{}.get();
//生成一个包含n个元素的std::数组,这些元素由const char*组成,指向Textx…Texty
模板
constexpr自动生成exthelper(std::integer_序列)无异常{
返回std::数组{{Converted.data()…};
}
//生成所需数量的文本
constexpr auto generateTextArray()noexcept{
返回generateTextHelper(std::make_integer_sequence());
}
}
//这是一个constexpr数组
constexpr auto text=ConstexprGenerator::generateTextArray();
int main(){
std::copy(text.begin()、text.end()、std::ostream_迭代器(std::cout,“\n”);
返回0;
}

使用MSVC、Clang和gcc测试

为什么粘贴汇编代码?而且,我想说OP不需要boostsolution@NutCracker通过汇编,我可以看到字符串附加是否在编译时完成,这对于宏来说确实有点多余,我已经删除了它,很抱歉,我仍然停留在STL场景中。
constepr auto strs\u array…
会告诉您它是在编译时发生还是在not@NutCracker泰,我明白了!它总是连续的编号吗?也就是说,它总是从
0
到某个
n
?是的,总是连续的。0。
Program returned: 0
Program stdout
test0
test1
test2
test3
test4
test5
test6
test7
test8
test9
test10
test11
test12
test13
test14
test15
test16
test17
test18
test19
#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;
}
test0
test1
test2
test3
test4
test5
test6
test7
test8
test9
test10
test11
test12
test13
test14
test15
test16
test17
test18
test19
#include <iostream>
#include <algorithm>
#include <iterator>
#include <array>
#include <string>

// Specification for the output that we want to generate
constexpr const char BaseString[]{ "text" };    // Some example text
constexpr size_t StartIndex = 1u;               // Start index. So first array element will be "Text1"
constexpr size_t NumberOfElements = 20u;        // Number of elements to create. Last array element will be "Text20"

// These templates are used to generate a std::array
namespace ConstexprGenerator {
    // To create something like "text123" as constexpr
    template <const size_t numberToConvert, const char* Text>
    class Converter {
    public:
        // Some helper variables for calculating sizes
        static constexpr size_t TextLength{ std::char_traits<char>::length(Text) };
        static constexpr size_t NumberOfDigits{ ([]() constexpr noexcept {size_t result = 0; int temp = numberToConvert; for (; temp != 0; temp /= 10) ++result; return result; }()) };
        static constexpr size_t ArrayLength{ (numberToConvert ? 1u : 2u) + NumberOfDigits + TextLength };

        // Here we will store the string
        std::array<char, ArrayLength> internalString{};

        // Constructor: Copy text and Convert number to character digits
        constexpr Converter() noexcept {
            size_t i{ 0 };  for (; i < TextLength; ++i) internalString[i] = Text[i]; // Copy text
            if (numberToConvert == 0) internalString[i] = '0';  // In case that the given number is 0, then simply copy '0' character   
            else {
                i = NumberOfDigits + TextLength - 1;            // Convert number to character digits
                int number = numberToConvert; for (; number; number /= 10)
                    internalString[i--] = number % 10 + '0';
            }
        }
        constexpr std::array<char, ArrayLength> get() const { return *this; };              // getter
        constexpr operator std::array<char, ArrayLength>() const { return internalString; } // type cast
    };

    // Templated variable. Will have always a different type, depending on the template parameters
    template<const size_t numberToConvert, const char* Text>
    constexpr auto Converted = Converter<numberToConvert, Text>{}.get();

    // Generate a std::array with n elements that consist of const char *, pointing to Textx...Texty
    template <int... ManyIntegers>
    constexpr auto generateTextHelper(std::integer_sequence<size_t, ManyIntegers...>) noexcept {
        return std::array<const char*, sizeof...(ManyIntegers)>{ {Converted<ManyIntegers + StartIndex, BaseString>.data()...}};
    }
    // Generate the required number of texts
    constexpr auto generateTextArray()noexcept {
        return generateTextHelper(std::make_integer_sequence<size_t, NumberOfElements>());
    }
}
// This is a constexpr array
constexpr auto text = ConstexprGenerator::generateTextArray();

int main() {
    std::copy(text.begin(), text.end(), std::ostream_iterator<const char*>(std::cout, "\n"));
    return 0;
}