问题描述
所以我一直在四处寻找不同的东西,但是我无法用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 ++ Standard越低越好。
进行编辑以帮助更好地理解问题。
解决方法
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
本质上是指向字符串常量的字符串跨度。因此,如果constexpr
的数据结构正在初始化,则frozen::string
永远不会进行分配,这就是为什么它可以对constexpr友好的原因。
冻结的容器具有与C ++ stdlib容器非常相似的API,但在构造后不可修改。此外,它们在运行时非常高效-映射基于在编译时创建完美的哈希表的基础,并且它们也不进行任何动态内存分配。
这是一个例子:
#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");
如果您有一堆字符串常量需要映射到软件的配置值,反之亦然,这将非常有用。
自C ++ 11起,在文件范围内已初始化const
的 constexpr
变量没有传统的静态初始化。这意味着,在输入main之前不调用其构造函数,不存在“静态初始化顺序失败”。相反,它们最终在可执行文件的BSS只读存储器段中具有正确的值。如果您有很多这样的映射,或者它们很大,那么由于不调用malloc并在输入main之前复制了很多字符串,因此可以显着地提高应用程序的启动时间。
https://github.com/serge-sans-paille/frozen
, std :: vector和std :: to_string()不是constexpr。
您的第二个函数示例将在不使用这些函数的情况下并且在使用case class User(id: String,name: String)
val oldUsers =
Seq(User("1","Test1"),User("2","Test2"),User("8","Test8"),User("9","Test9"))
val newUsers = Seq(User("1","UpdatedTest1"),User("10","UpdatedTest10"))
val oldAsMap = oldUsers.map(user => user.id -> user).toMap
val newAsMap = newUsers.map(user => user.id -> user).toMap
val ids = oldAsMap.keySet ++ newAsMap.keySet
val result = ids.map(id => newAsMap.getOrElse(id,oldAsMap(id))).toSeq
时工作,例如:
std::string_view
我相信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\0");
}
else if (k % 3 == 0){
sprintf(result[i],"Fizz\0");
}
else if (k % 5 == 0){
sprintf(result[i],"Buzz\0");
}
else {
sprintf(result[i],"%d\0",i+1);
}
}
return result;
}