gpt4 book ai didi

c++ - 在 C++ 中创建编译时键值映射

转载 作者:行者123 更新时间:2023-12-01 14:48:08 26 4
gpt4 key购买 nike

我试图创建一个编译时简单 C++ 中的键值映射。我正在编译 /std:c++11 .
(嵌入式代码使用IAR编译器,目前只支持cpp++11)

我学到了一点关于元编程的知识。

如果找不到键 ,我不希望我的 map 有默认值,
喜欢这篇文章:How to build a compile-time key/value store?

我想得到编译器错误,如果在我的代码中我试图获取一个未存储在 map 中的值。

这是我所做的:


#include <iostream>




template <int kk, int vv>
struct KeyValue
{
static const int k = kk, v = vv;
};


// Declaration
template <typename kv, typename...>
struct CompileTimeMap;


// Recursive Definition
template<typename kv, typename... rest>
struct CompileTimeMap<kv, rest...>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v : CompileTimeMap<rest...>::get<k_input>::val;
};
};


// Base Definition
template <typename kv>
struct CompileTimeMap<kv>
{
template<int k_input>
struct get
{
static const int val = (k_input == kv::k) ? kv::v;
};
};




// ----------------------------- Main -----------------------------

typedef CompileTimeMap<KeyValue<10, 20>, KeyValue<11, 21>, KeyValue<23, 7>> mymap;

int main()
{
// This calles should be ok !! :)
std::cout << mymap::get<10>::val << std::endl;
std::cout << mymap::get<11>::val << std::endl;
std::cout << mymap::get<23>::val << std::endl;


// This line should resolve a compile error !! (there is no key of 33)
std::cout << mymap::get<33>::val << std::endl;
}

我收到以下错误: error C2131: expression did not evaluate to a constant .

我怎样才能使这项工作?非常感谢 :)

最佳答案

不要在没有必要的地方编写模板元程序。试试这个简单的解决方案(CTMap 代表编译时间图):

template <class Key, class Value, int N>
class CTMap {
public:
struct KV {
Key key;
Value value;
};

constexpr Value operator[] (Key key) const
{
return Get (key);
}

private:
constexpr Value Get (Key key, int i = 0) const
{
return i == N ?
KeyNotFound () :
pairs[i].key == key ? pairs[i].value : Get (key, i + 1);
}

static Value KeyNotFound () // not constexpr
{
return {};
}

public:
KV pairs[N];
};


constexpr CTMap<int, int, 3> ctMap {{ { 10, 20 }, { 11, 21 }, { 23, 7 } }};


static_assert (ctMap[10] == 20, "Error.");
static_assert (ctMap[11] == 21, "Error.");
static_assert (ctMap[23] == 7, "Error.");

// constexpr auto compilationError = ctMap[404];

如果取消注释最后一行 ( live demo ),将会出现编译错误。编译器会将您定向到 KeyNotFound () :线,从
失败的原因应该是显而易见的。

评论
  • 成员变量pairs公开,以便可以使用列表初始化来初始化 map 。
  • 给定的N以及初始化 CTMap 的对数应该匹配。如果 N少,你会得到一个编译错误。如果 N更大,零初始化的对( { 0, 0 } )将被静默添加到 pairs .注意这一点。
  • (编译器生成的)构造函数不检查重复键。 operator[]会找到第一个,但预期的用法是您不初始化 CTMap有重复的键。
  • C++14 中不需要递归。我们可以写一个forconstexpr 中循环函数(live demo)。链接的实现提供了另一种想法,即在找不到 key 的情况下给出编译器错误:抛出异常。成员变量pairs被私有(private)化。

  • 打算在编译时使用

    这是一个线性映射,参数是按值传递的。我的意图是该映射将用于编译时评估的代码,这不应该是一个问题。

    另请注意,在运行时评估时,如果在 map 中找不到键,则此类不会提供任何反馈。

    让我们仔细看看 ctMap[10]在不同的情况下工作。我用三个编译器(MSVC v19.24、clang 10.0.0、gcc 9.3)尝试了以下方法。
  • constexpr int C = ctMap[10]; – 全局常量 C将初始化为 20即使在调试版本中。在运行时不进行计算。请注意,为确保将创建全局,您必须将其地址放在某个地方。如果使用 C 的值, 它的值 ( 20 ) 将在使用它的地方被替换,并且 C即使在调试版本中也不会在目标文件中创建。
  • int Foo () { return ctMap[10]; } – 在调试版本中 operator[]将被调用。在发布版本中 MSVC 内联 operator[]Foo ,即消除了一次调用,但生成的代码具有线性复杂度(编译器不强制在编译时进行计算,MSVC中的代码优化很差)。 Clang 和 gcc 编译一个 return 20; .

  • 这就是 ctMap[404]工作(使用相同的三个编译器):
  • constexpr int C = ctMap[404]; – 如上所述,不编译。
  • int Foo () { return ctMap[404]; } – 与 ctMap[10] 的备注相同, 但是 Foo将返回 0 .你不可能知道 404不在 map 上。要获取编译错误,Foo必须是 constexpr并被迫在编译时评估,例如将其分配给 constexpr变量或枚举器,在模板参数中使用它作为 C 数组的大小,在 static_assert 中等
  • 关于c++ - 在 C++ 中创建编译时键值映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61281843/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com