0

如果这是错误的网站,请提前道歉,如果是,请告诉我!

我编写了一个函数,用于检查某个是否存在于某个特定对象中std::map,并想知道这是否是一种使用的好习惯,以及是否有人可以提出任何改进意见。

std::map允许为该值接受多种数据类型。

union Variants {

    int asInt;
    char* asStr;


    Variants(int in) { asInt = in; }
    Variants() { asInt = 0;}
    Variants(char* in) { asStr = in; }

    operator int() { return asInt; }
    operator char*() { return asStr; }

};

template<typename T, typename Y>
bool in_map(T value, std::map<T, Y> &map)
{
     if(map.find(value) == map.end()) {
       return false;
   }else{
     return true;
   }
}

然后我可以主要使用以下内容:

 std::map<string, Variants> attributes;

 attributes["value1"] = 101;
 attributes["value2"] = "Hello, world";

 if(in_map<std::string, Variants>("value1", attributes))
 {
    std::cout << "Yes, exists!";
 }

任何帮助或建议将不胜感激。抱歉,如果这不符合规则或标准。谢谢!

4

3 回答 3

3

我在您的函数中看到的最大问题是您丢弃了生成的迭代器。

当您检查地图中是否存在键时,大多数情况下您希望在此之后检索/使用关联的值。在这种情况下使用您的函数会迫使您以性能为代价进行双重查找。我将完全避免使用该函数,并直接编写测试,保留迭代器以供以后使用以避免无用的查找:

auto it = map_object.find("key");
if (it != map_object.end())
    use(it->second);
else
    std::cout << "not found" << std::endl;

当然,如果您只是检查一个键是否存在并且不关心关联的值,那么您的功能很好(考虑到其他人在评论中告诉您的内容)但我认为它的用例非常有限而且不是真的值得额外的功能。你可以这样做:

if (map_object.find("key") != map_object.end())
    std::cout << "found, but I don't care about the value" << std::endl;
于 2013-09-05T23:18:25.837 回答
0

打字

if(in_map<std::string, Variants>("value1", attributes))

对我来说似乎有点过分,输入所有类型名语法让我只想使用该map.find函数而不是为了方便。但是,根据您的编译器,有时模板参数可以自动解释,例如,Visual Studio 将允许这样做:

if(in_map(std::string("value1"), attributes))

在这种情况下,我必须构造一个std::string对象来替换,但是我已经从调用中完全删除了模板定义,编译器仍然会根据给定的参数char*找出什么T和是什么。Y

但是,我推荐的建议是#define用来定义您的“功能”。虽然它不是一个真正的函数,因为#define实际上只是将代码片段直接替换到源代码中,它可以使事情变得更容易和视觉上吸引人:

#define in_map(value,map) (map.find(value) != map.end())

然后您使用它的代码将如下所示:

if(in_map("value1", attributes))

你们都得到了不使用函数调用的优化,以及像在 PHP 中那样的视觉外观。

于 2013-09-05T23:45:53.070 回答
0

关于改进的任何指针。

当然。

template<typename T, typename Y>
bool in_map(T value, const std::map<T, Y> &map)
{
     return map.find(value) != map.end();
}

我会将地图作为第一个参数(只是一个偏好)。此外,因为整个事情都适合单行,你甚至可能不需要这个功能。

您还丢弃了返回的迭代器,但由于您没有使用它,所以这不是问题。

除此之外,这在编码实践方面看起来还可以吗?即使用联合还是我可以使用其他类型,例如结构?

好吧,使用char*看起来不是一个好主意,因为这char*意味着您可以修改数据。char*也意味着这个指针是动态分配的,你delete[]以后可能想要那个指针。而且你不能在联合中使用析构函数。如果无法更改文本,您可以使用const char*,否则您可能需要使用不同的数据类型。另见三法则

下一个问题 - 您试图将 char* 和 int 放在同一位置。这意味着在某些时候您正试图将指针转换为整数。这是一个坏主意,因为在 64 位平台上,指针可能不适合 int,而且你只会得到它的一半。

此外,如果您尝试在同一个变量中存储多个不同的值,您并没有指出在任何地方存储了哪种类型。为此,您需要将联合封装到结构中并添加指示存储对象类型的字段(到结构中)。但是,在这种情况下,您最终将重新发明轮子。因此,如果您尝试存储“通用”类型,您可能需要查看Boost.AnyBoost.VariantQVariant。不过,所有这些都需要 BIG 外部库(boostQt)。

于 2013-09-05T23:28:56.553 回答