如何创建 constexpr std::vector<std::string> 或类似的东西?
How to create a constexpr std::vector<std::string> or something similar?
所以我一直在四处寻找并尝试不同的东西,但我无法理解我将如何使用 constexpr 创建一些字符串集合。
我想做的基本上是以下内容,显然无法编译:
constexpr std::vector<std::string> fizzbuzz(){
size_t N = 100;
std::vector<std::string> result;
result.reserve(N);
for (int i = 0; i < N; i++){
int k = i+1;
if(k % 5 == 0 && k % 3 == 0){
result.push_back("FizzBuzz");
}
else if(k % 5 == 0){
result.push_back("Buzz");
}
else if(k % 3 == 0){
result.push_back("Fizz");
}
else{
result.push_back(std::to_string(k));
}
}
return result;
}
如果我知道如何做像这样简单的事情,我会很高兴:
constexpr std::string fizzbuzz(int k){
if(k % 3 == 0) return "Fizz";
else return std::to_string(k);
}
我认为这只是向完整解决方案迈出的一小步。
不一定是 std::strings 也不一定是 std::vectors.
哦,C++ 标准越低越好。
已编辑以帮助更好地理解问题。
std::vector 和 std::to_string() 不是 constexpr。
您的第二个函数示例在没有这些的情况下也可以使用 std::string_view
,例如:
constexpr std::string_view fizzbuzz(const int k){ if(k % 3 == 0) return "Fizz"; else return "Buzz"; }
我相信std::string_view是c++17
所以在@Jarod42的帮助下我终于解决了:
请参阅评论以了解为什么要划线。
template <int N>
constexpr std::array<char[9], N> solution8(){
std::array<char[9], N> result{};
for(int i = 0; i < N; i++){
int k = i + 1;
if ((k % 3 == 0) && (k % 5 == 0)){
sprintf(result[i], "FizzBuzz[=10=]");
}
else if (k % 3 == 0){
sprintf(result[i], "Fizz[=10=]");
}
else if (k % 5 == 0){
sprintf(result[i], "Buzz[=10=]");
}
else {
sprintf(result[i], "%d[=10=]", i+1);
}
}
return result;
}
std::vector
/std::string
在 C++20 之前没有 constexpr
构造函数...
即使在 C++20 中,constexpr
分配也不应从 constexpr 求值中逃脱,因此不能在运行时使用(用于打印)。
我没有看到将整数转换为 char 序列表示的标准 constexpr 方法。
std::to_string
、std::to_chars
、std::format
不是 constexpr
。
因此,您可以使用 std::tuple
而不是同构容器,例如 (C++17):
template <std::size_t I>
constexpr auto fizzbuzz_elem()
{
if constexpr (I % 5 == 0 && I % 3 == 0) {
return "FizzBuzz";
} else if constexpr (I % 5 == 0) {
return "Buzz";
} else if constexpr (I % 3 == 0){
return "Fizz";
} else {
return I;
}
}
template <std::size_t...Is>
constexpr auto fizzbuzz_impl(std::index_sequence<Is...>){
return std::make_tuple(fizzbuzz_elem<1 + Is>()...);
}
template <std::size_t N>
constexpr auto fizzbuzz(){
return fizzbuzz_impl(std::make_index_sequence<N>());
}
int main() {
constexpr auto res = fizzbuzz<42>();
std::apply([](auto... e){ ((std::cout << e << std::endl), ...); }, res);
}
做这种事情的一种方法是使用 frozen
库,它在 C++14 中工作,它的一部分在 C++11 中工作。 (我们在一些 C++11 代码的生产中使用了它。)
图书馆提供了一些东西来实现 constexpr
:
虽然 std::string
最终可以调用动态内存分配器,但这并不 constexpr
友好(除非他们在我错过的最新标准中取得了重大进展?)frozen::string
是基本上是一个 string-span 指向一个字符串常量。因此,如果您的数据结构正在 constexpr
初始化,frozen::string
永远不会进行分配,这就是为什么它可以是 constexpr 友好的。
冻结容器与 C++ stdlib 容器非常相似 API,但它们在构造后不可修改。此外,它们在 run-time 方面非常高效——这些映射基于在编译时创建一个完美的散列 table,并且它们也不进行任何动态内存分配。
这是一个例子:
#include <frozen/unordered_map.h>
#include <frozen/string.h>
constexpr frozen::unordered_map<frozen::string, int, 2> olaf = {
{"19", 19},
{"31", 31},
};
constexpr auto val = olaf.at("19");
如果您有一堆字符串常量需要映射到软件的配置值,或者 vice-versa。
,这将非常有用
const
file-scope 处的 constexpr
初始化的变量自 C++11 以来没有传统的静态初始化。这意味着,在进入 main 之前不会调用它们的构造函数,不存在“静态初始化顺序失败”。相反,它们最终出现在 executable 的 BSS read-only 内存段中,并且正确的值已经到位。如果您有很多这样的映射或者它们很大,这可以显着缩短应用程序的启动时间,因为在输入 main 之前不调用 malloc 并复制大量字符串。
所以我一直在四处寻找并尝试不同的东西,但我无法理解我将如何使用 constexpr 创建一些字符串集合。
我想做的基本上是以下内容,显然无法编译:
constexpr std::vector<std::string> fizzbuzz(){
size_t N = 100;
std::vector<std::string> result;
result.reserve(N);
for (int i = 0; i < N; i++){
int k = i+1;
if(k % 5 == 0 && k % 3 == 0){
result.push_back("FizzBuzz");
}
else if(k % 5 == 0){
result.push_back("Buzz");
}
else if(k % 3 == 0){
result.push_back("Fizz");
}
else{
result.push_back(std::to_string(k));
}
}
return result;
}
如果我知道如何做像这样简单的事情,我会很高兴:
constexpr std::string fizzbuzz(int k){
if(k % 3 == 0) return "Fizz";
else return std::to_string(k);
}
我认为这只是向完整解决方案迈出的一小步。 不一定是 std::strings 也不一定是 std::vectors.
哦,C++ 标准越低越好。
已编辑以帮助更好地理解问题。
std::vector 和 std::to_string() 不是 constexpr。
您的第二个函数示例在没有这些的情况下也可以使用 std::string_view
,例如:
constexpr std::string_view fizzbuzz(const int k){ if(k % 3 == 0) return "Fizz"; else return "Buzz"; }
我相信std::string_view是c++17
所以在@Jarod42的帮助下我终于解决了:
请参阅评论以了解为什么要划线。
template <int N>
constexpr std::array<char[9], N> solution8(){
std::array<char[9], N> result{};
for(int i = 0; i < N; i++){
int k = i + 1;
if ((k % 3 == 0) && (k % 5 == 0)){
sprintf(result[i], "FizzBuzz[=10=]");
}
else if (k % 3 == 0){
sprintf(result[i], "Fizz[=10=]");
}
else if (k % 5 == 0){
sprintf(result[i], "Buzz[=10=]");
}
else {
sprintf(result[i], "%d[=10=]", i+1);
}
}
return result;
}
std::vector
/std::string
在 C++20 之前没有 constexpr
构造函数...
即使在 C++20 中,constexpr
分配也不应从 constexpr 求值中逃脱,因此不能在运行时使用(用于打印)。
我没有看到将整数转换为 char 序列表示的标准 constexpr 方法。
std::to_string
、std::to_chars
、std::format
不是 constexpr
。
因此,您可以使用 std::tuple
而不是同构容器,例如 (C++17):
template <std::size_t I>
constexpr auto fizzbuzz_elem()
{
if constexpr (I % 5 == 0 && I % 3 == 0) {
return "FizzBuzz";
} else if constexpr (I % 5 == 0) {
return "Buzz";
} else if constexpr (I % 3 == 0){
return "Fizz";
} else {
return I;
}
}
template <std::size_t...Is>
constexpr auto fizzbuzz_impl(std::index_sequence<Is...>){
return std::make_tuple(fizzbuzz_elem<1 + Is>()...);
}
template <std::size_t N>
constexpr auto fizzbuzz(){
return fizzbuzz_impl(std::make_index_sequence<N>());
}
int main() {
constexpr auto res = fizzbuzz<42>();
std::apply([](auto... e){ ((std::cout << e << std::endl), ...); }, res);
}
做这种事情的一种方法是使用 frozen
库,它在 C++14 中工作,它的一部分在 C++11 中工作。 (我们在一些 C++11 代码的生产中使用了它。)
图书馆提供了一些东西来实现 constexpr
:
虽然 std::string
最终可以调用动态内存分配器,但这并不 constexpr
友好(除非他们在我错过的最新标准中取得了重大进展?)frozen::string
是基本上是一个 string-span 指向一个字符串常量。因此,如果您的数据结构正在 constexpr
初始化,frozen::string
永远不会进行分配,这就是为什么它可以是 constexpr 友好的。
冻结容器与 C++ stdlib 容器非常相似 API,但它们在构造后不可修改。此外,它们在 run-time 方面非常高效——这些映射基于在编译时创建一个完美的散列 table,并且它们也不进行任何动态内存分配。
这是一个例子:
#include <frozen/unordered_map.h>
#include <frozen/string.h>
constexpr frozen::unordered_map<frozen::string, int, 2> olaf = {
{"19", 19},
{"31", 31},
};
constexpr auto val = olaf.at("19");
如果您有一堆字符串常量需要映射到软件的配置值,或者 vice-versa。
,这将非常有用const
file-scope 处的 constexpr
初始化的变量自 C++11 以来没有传统的静态初始化。这意味着,在进入 main 之前不会调用它们的构造函数,不存在“静态初始化顺序失败”。相反,它们最终出现在 executable 的 BSS read-only 内存段中,并且正确的值已经到位。如果您有很多这样的映射或者它们很大,这可以显着缩短应用程序的启动时间,因为在输入 main 之前不调用 malloc 并复制大量字符串。