我正在开发一个C ++项目(Embarcadero C ++ Builder),其中许多类(都在同一名称空间中)需要从颜色名称中获取颜色值。为了实现这一点,我在一个单独的代码Tools.cpp中创建了一个由所有类使用的函数getColorCode(),如下所示:
#include "Tools.h"
namespace mynamespace {
int getColorCode(std::string Name)
{
if (Name == "red") return(0xFF0000);
else if (Name == "green") return(0x00FF00);
else if (Name == "blue") return(0x0000FF);
// many more else ifs
else return(0x000000);
}
}
头文件是:
#ifndef MYNAMESPACE_TOOLS_H
#define MYNAMESPACE_TOOLS_H
#include <string>
namespace mynamespace {
int getColorCode(std::string Name);
}
#endif
这样可行,但我希望将所有颜色定义存储在地图中以避免数百个其他ifs。我的问题是,我无法在Tools.cpp的头文件中定义类似std::map<std::string, int> ColorNames;
的内容而不在定义地图的行中获取W8058 Cannot create pre-compiled header
。另外,我得到几个链接器警告,mynamespace :: ColorNames是在每个类中定义的,包括Tools.h。
我计划通过检查map.empty()在第一次调用getColorCode()时填充地图,并将所有颜色名称和代码添加到它,如果它是空的,那么进一步调用将只搜索地图
另一个尝试是为此创建工具类并在构造函数中初始化地图。但是然后每个使用它的类都会创建一个自己的实例,这是我不想要的。阅读关于单身人士的讨论并尝试提出的代码并没有帮助。
有没有任何实用的方法来实现这个或者我会留在丑陋的(非高性能的)if-then-else链中?
感谢任何提示,Armin
答案 0 :(得分:1)
如果你可以使用C ++ 11(我不熟悉C ++ - builder),你可以像这样初始化函数中的静态地图
int getColorCode(std::string name) {
static std::map<std::string, int> colors{
{ "red", 0xFF0000 },
{ "green", 0x00FF00 },
// ... etc
};
// rest of logic.
}
这样做的好处是地图本地化为函数,只初始化一次,无法从外部访问。
如果您没有C ++ 11功能(再次,我不知道编译器),只需检查地图是否为空,如您所说,并填写它。我仍然会将它标记为静态,但全局变量都很糟糕。
答案 1 :(得分:0)
文件级静态接缝在这里适合我,但是你需要在初始化时处理竞争条件。但是我可能会建议只为int替换的颜色名称创建宏。或者是一个拥有所有const memebers的类
文件级静态
static std::map<string,int> Colors;
static std::mutex lck;
int getColorCode(std::string Name)
{
// Get a lock here if you are not single threaded
lck.lock()
if(Colors.empty())
{...}
lck.unlock()
}
或具有所有颜色的类
class Colors
{
Colors():
red(0xFF0000)
{
}
int red;
}
答案 2 :(得分:0)
我会使用简单的struct
声明而不是地图。只要您不会有数百万条记录,这就不应该让您在使用std::map
时获得显着的性能影响。如果它符合您对 n 条目的需求,请检查 O(n) vs O(log n)复杂性,但我认为n在范围内数百(如你所提到的)不应该也是。
就在.cpp内:
namespace {
struct ColorDef
{
std::string name;
int colorValue;
};
ColorDef colorValueDefs[] = {
// Put your entries here:
{ "red", 0xFF0000 } ,
{ "green", 0x00FF00 } ,
{ "blue", 0x0000FF } ,
// etc. ...
// { "" , -1 } // have an end marker if you don't want to use sizeof()
// to iterate through
};
}
namespace mynamespace {
int getColorCode(std::string Name) {
// Make it thread safe if necessary:
// static std::mutex mtx;
// std::lock(mtx);
for(int i = 0; i < sizeof(colorValueDefs); ++i) {
if(Name == colorValueDefs[i].name) {
return colorValueDefs[i].colorValue;
}
}
return -1;
}
}
如果您可以使用c++11标准语法,则可以使用与上面显示的std::map
数组相同的方式初始化colorValueDefs
。
<强>更新强>
好吧,我想我一直在告诉废话邻居查询表现!如果我正确地得到了图表,性能命中率会以非常低的 n 数量出现,请查看图表:n = 10
我不确定在这里获得 O(n) / O(log n)的正确表示形式: - / ...
性能明智的std::map
应该是更好的选择!在第一次调用函数时初始化时会受到轻微的影响,或者在使用c++11初始值设定项列表功能初始化地图时可以避免这种情况。
答案 3 :(得分:-1)
只需将地图放在源文件中,然后使用该函数从中检索值:
#include "Tools.h"
namespace mynamespace {
std::map<std::string, int> ColorNames;
int getColorCode(std::string Name)
{
// do some error checking
// assume ColorNames has already been populated somehow
return ColorNames[Name];
}
}