3

我正在开发一个 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

这可行,但我希望将所有颜色定义存储在地图中以避免数百个 else if。我的问题是,如果不到达定义地图的行,我就无法std::map<std::string, int> ColorNames;在 Tools.cpp 的头文件中定义类似的东西。W8058 Cannot create pre-compiled header此外,我收到几个链接器警告,表明 mynamespace::ColorNames 在包括 Tools.h 在内的每个类中都定义了。

我的计划是在第一次调用 getColorCode() 时通过检查 map.empty() 来填充地图,并将所有颜色名称和代码添加到其中,如果它是空的,那么进一步的调用只会搜索地图。

另一种尝试是为此创建一个工具类并在构造函数中初始化地图。但是每个使用它的类都会创建一个它自己的实例,这是我不想要的。阅读关于单例的讨论并尝试提出的代码并没有帮助。

是否有任何实用的方法来实现这一点,或者我应该留在丑陋的(非性能)if-then-else 链中吗?

感谢您的任何提示,阿明

4

4 回答 4

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 功能(同样,我不知道编译器),只需像您说的那样检查映射是否为空,然后填充它。不过,我仍然会将其标记为静态,全局变量不好。

于 2013-10-24T18:31:40.643 回答
0

文件级静态接缝在这里适合我,但您需要在初始化时处理竞争条件。但是,我可能建议只为由 int 替换的颜色名称创建宏。或者一个拥有所有 const 成员的类

文件级静态

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; 
}
于 2013-10-24T18:31:40.623 回答
0

我会使用简单的struct声明而不是地图。只要您不会有数百万个条目,与使用std::map. 检查O(n)O(log n)复杂性是否适合您对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;
    }
}

如果您可以使用标准语法,则可以像上面显示的数组std::map一样初始化 a。colorValueDefs

更新
好的,我想我一直在说废话,但在这里查找性能!如果我得到正确的图表,性能影响开始出现在非常低的n数量,检查图表:n = 10
我不确定在这里得到O(n) / O(log n)的正确表示:-/ ...
std::map应该是比性能更好的选择!初始化器列表功能初始化地图时可以避免这种情况。

于 2013-10-24T18:35:24.423 回答
-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];
    }
 }
于 2013-10-24T18:29:44.480 回答