Roi*_*iT7 9 c++ templates metaprogramming key-value template-meta-programming
我尝试在 C++ 中创建一个编译时简单的键值映射。我正在编译/std:c++11. (使用IAR编译器进行嵌入代码,目前仅支持cpp++11)
我了解了一些关于元编程的知识。
如果找不到键,我不希望我的映射具有默认值,例如这篇文章:如何构建编译时键/值存储?
如果在我的代码中我试图获取未存储在映射中的值,我想得到编译器错误。
这是我所做的:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:error C2131: expression did not evaluate to a constant。
我怎样才能做到这一点?非常感谢 :)
如果没有必要,不要编写模板元程序。尝试这个简单的解决方案(CTMap代表编译时映射):
template <class Key, class Value, int N>\nclass CTMap {\npublic:\n struct KV {\n Key key;\n Value value;\n };\n\n constexpr Value operator[](Key key) const\n {\n return Get(key);\n }\n\nprivate:\n constexpr Value Get(Key key, int i = 0) const\n {\n return i == N ?\n KeyNotFound() :\n pairs[i].key == key ? pairs[i].value : Get(key, i + 1);\n }\n\n static Value KeyNotFound() // not constexpr\n {\n return {};\n }\n\npublic:\n KV pairs[N];\n};\n\n\nconstexpr CTMap<int, int, 3> ctMap{{ { 10, 20 }, { 11, 21 }, { 23, 7 } }};\n\n\nstatic_assert(ctMap[10] == 20, "Error.");\nstatic_assert(ctMap[11] == 21, "Error.");\nstatic_assert(ctMap[23] == 7, "Error.");\n\n// constexpr auto compilationError = ctMap[404];\nRun Code Online (Sandbox Code Playgroud)\n如果取消最后一行的注释(现场演示) ,您将收到编译错误。编译器将引导您到该KeyNotFound() :行,从该行失败的原因应该是显而易见的。
pairs被公开,以便可以使用聚合初始化来初始化映射。N和初始化的对的数量CTMap应该匹配。如果N小于,则会出现编译错误。如果N更大,则零初始化对 ( { 0, 0 }) 将默默地添加到pairs。请注意这一点。operator[]会找到第一个,但预期用途是不使用CTMap重复的键进行初始化。for我们可以在函数中编写循环constexpr(现场演示)。链接的实现提供了另一种想法,即在找不到密钥的情况下给出编译器错误:抛出异常。成员变量pairs设为私有。这是一个线性映射,参数按值传递。我的意图是该映射将在编译时评估的代码中使用,这应该不是问题。
\n另请注意,在运行时评估时,如果在映射中未找到该键,此类将不会提供任何反馈。
\n让我们仔细看看ctMap[10]不同情况下的工作原理。我已经使用三个编译器(MSVC v19.24、clang 10.0.0、gcc 9.3)尝试了以下操作。
constexpr int C = ctMap[10];\xe2\x80\x93即使在调试版本中C也会初始化全局常量。20运行时不进行任何计算。请注意,为了确保创建全局变量,您必须将其地址放在某处。如果您使用 的值C,则其值 ( 20) 将在使用它的地方被替换,并且C即使在调试版本中也不会在目标文件中创建。int Foo() { return ctMap[10]; }\xe2\x80\x93 在调试版本中将operator[]被调用。在发布版本中,MSVC 内联operator[]到Foo,即消除了一次调用,但生成的代码具有线性复杂度(编译器不会被迫在编译时进行计算,并且 MSVC 中的代码优化很差)。Clang 和 gcc 编译一个return 20;.这就是ctMap[404]工作原理(使用相同的三个编译器):
constexpr int C = ctMap[404];\xe2\x80\x93 如上所述,无法编译。int Foo() { return ctMap[404]; }\xe2\x80\x93 与 相同的注释适用ctMap[10],但Foo将返回0。你不可能知道,那404不在地图上。要获得编译错误,Foo必须constexpr并强制在编译时进行计算,例如将其分配给constexpr变量或枚举器,在模板参数中使用它,作为 C 数组的大小,在static_assert等中。| 归档时间: |
|
| 查看次数: |
4952 次 |
| 最近记录: |