【问题标题】:Best practice for "unused template parameter" in C++C++ 中“未使用的模板参数”的最佳实践
【发布时间】:2014-06-26 00:22:59
【问题描述】:

给定一个模板类,例如

template <class Key, class Value> 
class CustomMap {
    // standard map implementation here, with (say) 'put', 'contains' and 'get'
};

假设我不关心 Value 参数(因为我希望将地图作为一个集合使用),并且我不能使用标准 C++ 容器,那么推荐的方式是什么?

一种选择是使用 typedef:

typedef UNUSED int;
const UNUSED UNUSED_VALUE = 0;
CustomMap<std::string, UNUSED> map;
map.put("test", UNUSED_VALUE);
cout << map.contains("test");

在这种情况下你会推荐什么?显然,CustomMap&lt;std::string, void&gt; 无法编译,因为对 void 的引用无效。我无法更改CustomMap 的实现,也无法添加CustomSet 来补充它。

注意:这些要求来自教育环境;因此,正在寻求最具可读性和可理解性的答案。这个答案很可能是“添加评论解释你为什么使用 int”......

【问题讨论】:

  • 您可能希望使用char 而不是int,因为它占用的内存更少,但我不确定这是否最终会影响您的自定义集/映射...为什么不使用 std ::设置?。
  • 我的建议是“不要这样做”。集合不是地图。
  • 您应该使用struct dummy_struct{};不是 int)。而且您应该将整个内容包装在您自己的类中,以便将map 适应set 的麻烦只在一个地方。
  • 基于比较器构建数据结构,然后使用该数据结构提供两个接口:set 和 map 有什么问题,就像大多数 STL 实现都有底层平衡树一样结构和不同的接口?当前的方法将要求您在仅将其用作一个集合时浪费一些空间(您仍然需要将值,至少 1 个字节,加上填充)添加到每个节点......现在我想到了,它对你的期望可能有点过分,但你会真正从经验中学习。
  • 我不确定是否需要花费大量时间来完成重构,您可能可以将现有的CustomMap 重写为SortedTree,然后构建MapSet在一两个小时内达到顶峰。学生可能会有些困惑,但可能会将现有解决方案推广到更强大的东西。

标签: c++ templates void


【解决方案1】:

您可以使用一个空类,而不是为int 使用一个有点混乱的别名:

struct nothing {};
CustomMap<std::string, nothing> map;
map.put("test", nothing());

我也不会使用 SHOUTY_CAPS;除了更难阅读之外,它们通常保留给宏,以减少预处理器踩踏语言级名称的危险。

【讨论】:

  • 谢谢 - 正是我想要的。简短,不言自明,找到匹配值时不会乱七八糟
  • 您还可以添加一个包装方法,如CustomMap&lt;Key, Value&gt;::insert(const Key&amp; key) { Impl::put(Key, Value()); }(其中Impl 是实现类),这样您就可以简单地说map.insert("test");,它看起来更像一个集合。
  • @tucuxi 默认模板参数可以帮助解决这种情况,例如:template&lt;typename Key , typename Value = dummy_tag&gt; 甚至template&lt;typename key , typename value = key&gt;(后者与std::set 非常相似,其中键和值相同) .这两个选项都与部分专业化配合得很好。其他解决方案(通过 C++11 模板别名)可能是 template&lt;typename Key&gt; using CustomSet = CustomMap&lt;Key,dummy_tag&gt;; 多亏了别名,用法更加清晰。
  • @tucuxi 最后为了让你的ADT的界面更清晰,我建议你把put类函数的值参数设为可选(假设Value是默认可构造的):put( const Key&amp; key , const Value&amp; value = Value{} );如果没有,可以使用 SFINAE 和 std::is_default_constructible trait。
【解决方案2】:

就个人而言,如果他们必须同名,我可能会使用专业化:

template <typename T, typename... J>
class OptionalSet;

template <typename T>
class OptionalSet
{
  //implementation of non-keyed thing
};

template <typename T, typename J>
class OpionalSet
{
  //implimentation of keyed thing
};

但最重要的是set和map不一样,把它们变成同一个class就是自找麻烦。

【讨论】:

  • 谢谢,但这对于预期的设置来说太冗长了:教室,使用现有的地图实现并针对特定问题即兴创作一个集合。
  • 是的,可变参数宏是一个很酷的新功能。不,我不认为这是一个很好的用途。只有两种实现,你需要专攻。只需提供OptionalSet&lt;K&gt;OptionalSet&lt;K,V&gt; 两个实现并调用它们SetMap
猜你喜欢
  • 2014-12-10
  • 1970-01-01
  • 2012-09-05
  • 1970-01-01
  • 1970-01-01
  • 2019-02-10
  • 2013-10-27
  • 2016-02-27
  • 2016-12-24
相关资源
最近更新 更多