使用模板减少const和非const非成员函数的代码重复问题

5

我有以下两个函数:

Thing* find_thing_by_name(const String & name, Map<String,Thing*> & thing_map)
{
    auto it = thing_map.find(name);
    return it->second;
}
const Thing* find_thing_by_name(const String & name, const Map<String,Thing*> & thing_map)
{
    auto it = thing_map.find(name);
    return it->second;
}

这只是一个我想解决的问题的简单示例。

这些函数具有完全相同的主体,但我需要两者来处理我的地图的const和非const版本。我已经看到了使用const cast处理成员函数的方法,但这些是非成员函数,我希望使用模板解决此问题。我该如何编写一个模板函数以减少代码重复?我甚至不确定从哪里开始。


不是直接回答你的问题,只是一个建议:你可以在Thing中添加一个成员变量,比如m_AllowChange,根据它是false还是true,允许对Thing进行更改。但当然,这种便利性取决于Thing类有多复杂。 - macroland
2个回答

4
你可以:
template <typename MAP>
auto find_thing_by_name(const String & name, MAP & thing_map)
{
    auto it = thing_map.find(name);
    return it->second;
}

那么

String s = ...;
Map<String,Thing*> nonconst_m = ...;
const Map<String,Thing*> const_m = ...;
find_thing_by_name(s, nonconst_m); // MAP is deduced as Map<String,Thing*>
                                   // thing_map's type is Map<String,Thing*>&
find_thing_by_name(s, const_m);    // MAP is deduced as const Map<String,Thing*>
                                   // thing_map's type is const Map<String,Thing*>&

哇,真的这么简单吗?编译器如何知道类型MAP有一个查找方法? - Dillydill123
1
@Dillydill123 这取决于你。如果你传递了某些不支持的内容,你会得到编译错误。 - songyuanyao

0

我觉得你对这个问题想得太多了。在方法中使用相同的代码来处理两种不同的参数变化(通过const引用和非const引用传递)意味着你的代码在方法中不修改这个参数(只调用它的const方法)。否则,相同的代码在const引用上将无法编译。这意味着你应该只实现这个方法的一个版本,因为你始终可以在带有const Map &thing_map形式参数的方法中传递非const thing_map实际参数。 此外,在你的实际例子中没有必要返回const Thing*,因为它->second仍然是Thing*而不是const Thing*。 所以这是我的建议:

Thing* find_thing_by_name(const String & name, const Map<String,Thing*> & thing_map)
{
    auto it = thing_map.find(name);
    return it->second;
}

或者如果您想限制对Thing对象的访问,请仅实现此版本:

const Thing* find_thing_by_name(const String & name, const Map<String,Thing*> & thing_map)
{
    auto it = thing_map.find(name);
    return it->second;
}

然后你可以这样使用其中任意一种变体:

...
const Map<String, Thing *> constMapObj;
const Map<String, Thing *> nonConstMapObj;
....
auto res1 = find_thing_by_name(someKey, constMapObj);
auto res2 = find_thing_by_name(someOtherKey, nonConstMapObj);

你不能像那样重载它,编译器会根据参数决定调用哪个函数。由于你的参数在两个重载中都相同,所以这是不明确的。 - greatwolf
我的意思不是要进行重载,只需要一个实现。上面的答案类似,只是在语义上常量方法中通过非const引用传递参数。 - user3414895

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接