如何在编译时创建具有 string_views 序列的 constexpr 数组?

如何解决如何在编译时创建具有 string_views 序列的 constexpr 数组?

我想创建一个 constexpr std::array<std::string_view,ConstexprNumber>。例如,它应该包含 constexpr std::strings_view's,如下所示:

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

但是,当然,“makeString”函数不会做我想要的。或者说,我不知道如何实施正确的解决方案。

我们怎样才能让这样的数组工作呢?是基于这个初始解决方案还是类似的解决方案?

解决方法

您可以执行以下操作:

constexpr size_t NumberOfTextsToGenerate = 10u;

template <std::size_t I>
struct digit_to_end_impl {
    static constexpr const char value[]{ 't','e','x','t',(I + '0'),0 };
};

template <std::size_t I>
struct digit_to_end {
    static constexpr std::string_view value = digit_to_end_impl<I>::value;
};

template <std::size_t I>
constexpr std::string_view makeString() {
    return digit_to_end<I>::value;
}

template <unsigned int... ManyIntegers>
constexpr auto generateTextHelper(std::integer_sequence<unsigned int,ManyIntegers...>) {
    return std::array<std::string_view,sizeof...(ManyIntegers)>{ { makeString<ManyIntegers>()... } };
}

// ...

查看DEMO

但是,当 NumberOfTextsToGenerate 大于 10 时,这将不起作用。

,

哇哦,我终于做到了!!!

(链接到 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,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

编辑:支持 wchar_t 字符串。

,

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

因为 SO 用户提供了许多很好的答案以及对我的问题 here 的其他答案,

我现在将使用以下代码。

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

使用 MSVC、Clang 和 gcc 进行测试

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-