我可能正在尝试实现不可能的事情,但StackExchange总是令我感到惊讶,所以请大家多说:
我需要将名称映射到整数。名字(约2k)是独一无二的。该列表不会有任何添加或删除,并且这些值在运行时不会更改。
将它们实现为const int
变量,可以对存在和类型进行编译时检查。
这在代码中也非常清晰和冗长。很容易发现错误。
将它们实现为std::map<std::string, int>
为我提供了很多灵活性,可以构建名称以查找字符串操作。我可以使用它来将字符串作为参数提供给函数,这些函数可以通过在该字符串后附加前缀/后缀来查询列表中的多个值。我还可以通过从循环变量创建键名的数字部分来循环遍历多个值。
现在我的问题是:是否有一种结合两种优势的方法?缺少编译时检查(特别是对于密钥存在)几乎杀死了我的第二种方法。 (特别是std::map
如果密钥不存在而无声地返回0
,这会产生难以发现的错误。)但循环和前/后缀添加功能非常有用。
我更喜欢不使用任何其他库(如boost)的解决方案,但请尽可能建议它们,因为我可能无论如何都可以重新实现它们。
关于我对地图做什么的一个例子:
void init(std::map<std::string, int> &labels)
{
labels.insert(std::make_pair("Bob1" , 45 ));
labels.insert(std::make_pair("Bob2" , 8758 ));
labels.insert(std::make_pair("Bob3" , 436 ));
labels.insert(std::make_pair("Alice_first" , 9224 ));
labels.insert(std::make_pair("Alice_last" , 3510 ));
}
int main()
{
std::map<std::string, int> labels;
init(labels);
for (int i=1; i<=3; i++)
{
std::stringstream key;
key << "Bob" << i;
doSomething(labels[key.str()]);
}
checkName("Alice");
}
void checkName(std::string name)
{
std::stringstream key1,key2;
key1 << name << "_first";
key2 << name << "_last";
doFirstToLast(labels[key1.str()], labels[key2.str()]);
}
另一个目标是main()
例程中显示的代码尽可能简单和冗长。 (需要非程序员理解。)init()
函数将由某些工具代码生成。 doSomething(int)
函数是固定的,但我可以在它们周围编写包装函数。像checkName()
这样的助手可能会更复杂,但需要易于调试。
答案 0 :(得分:1)
我不确定我是否了解您的所有要求,但不使用std::map
这样的事情怎么样。
我假设你有三个字符串,“FIRST”,“SECOND”和“THIRD”
想要分别映射到42,17和37。
#include <stdio.h>
const int m_FIRST = 0;
const int m_SECOND = 1;
const int m_THIRD = 2;
const int map[] = {42, 17, 37};
#define LOOKUP(s) (map[m_ ## s])
int main ()
{
printf("%d\n", LOOKUP(FIRST));
printf("%d\n", LOOKUP(SECOND));
return 0;
}
缺点是您不能将变量字符串与LOOKUP
一起使用。但现在你可以迭代这些值了。
答案 1 :(得分:1)
也许是这样的(未经测试)?
struct Bob {
static constexpr int values[3] = { 45, 8758, 436 };
};
struct Alice {
struct first {
static const int value = 9224;
};
struct last {
static const int value = 3510;
};
};
template <typename NAME>
void checkName()
{
doFirstToLast(NAME::first::value, NAME::last::value);
}
...
constexpr int Bob::values[3]; // need a definition in exactly one TU
int main()
{
for (int i=1; i<=3; i++)
{
doSomething(Bob::values[i]);
}
checkName<Alice>();
}
答案 2 :(得分:1)
实现示例的一种方法是使用枚举和令牌粘贴,如此
enum {
Bob1 = 45,
Bob2 = 8758,
Bob3 = 436,
Alice_first = 9224,
Alice_last = 3510
};
#define LABEL( a, b ) ( a ## b )
int main()
{
doSomething( LABEL(Bob,1) );
doSomething( LABEL(Bob,2) );
doSomething( LABEL(Bob,3) );
}
void checkName()
{
doFirstToLast( LABEL(Alice,_first), LABEL(Alice,_last) );
}
这是否最佳取决于名称的来源。
如果您需要支持for循环用例,请考虑
int bob[] = { 0, Bob1, Bob2, Bob3 }; // Values from the enum
int main()
{
for( int i = 1; i <= 3; i++ ) {
doSomething( bob[i] );
}
}
答案 3 :(得分:0)
使用枚举你有两个编译时检查,你可以循环它: