7

我可能正在尝试实现不可能的目标,但 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() 可能更复杂,但需要易于调试。

4

4 回答 4

1

I'm not sure I understand all your requirements, but how about something like this, without using std::map. I am assuming that you have three strings, "FIRST", "SECOND" and "THIRD" that you want to map to 42, 17 and 37, respectively.

#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;
}

The disadvantage is that you cannot use variable strings with LOOKUP. But now you can iterate over the values.

于 2013-09-01T14:32:16.217 回答
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>();
}
于 2013-09-01T16:37:05.060 回答
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] );
  }
}
于 2013-09-01T18:57:44.200 回答
0

使用 enum 你有编译时检查,你可以循环它:

如何迭代枚举?

于 2013-09-01T14:40:24.173 回答