【问题标题】:How to break this circular typedef?如何打破这个循环 typedef?
【发布时间】:2010-11-12 22:28:44
【问题描述】:

我想声明几个类型 (在KV 上模板化的类内部并提供一些缓存行为):

typedef std::map<
  long long,
  typename key_to_value_type::iterator  // Ooops... not declared yet
> timestamp_to_key_type;

typedef std::map<
  K,
  std::pair<V,typename timestamp_to_key_type::iterator> 
> key_to_value_type;

当然这是不可能的,因为循环定义。 我可以用void* 破解它,但我想知道是否有一些前向声明魔法或其他技术可以更好地完成这项工作。

(是的,我知道boost::bimap 会回避这个问题)。

【问题讨论】:

  • 您是否尝试使用数据构建地图,然后以不同的顺序对该地图建立索引? (大概是为了快速查找)
  • 当我在玩弄一些已经在工作的 LRU 缓存代码时,这个问题出现了(基本上是一个补充了跟踪的键值映射,因此可以在需要时清除最近最少使用的记录)。原始版本的每个映射的值都保存另一个映射的键类型,但是一些 O(log n) 访问可以压缩为使用上面的形式直接迭代器访问。但我不希望这个问题变成关于 LRU 缓存实现的优点的辩论!更重要的是我意识到我不知道如何最好地处理这种 typedef/forward-declaration 问题。
  • +1 这是个好问题。要是我知道你想表达什么类型就好了。
  • 有关此问题的更多详细信息,请参阅bottlenose.demon.co.uk/article/lru.htm

标签: c++ stl iterator typedef forward-declaration


【解决方案1】:

不可能,考虑一下类型:

timestamp_to_key_type
= map< long long, key_to_value_type::iterator >
= map< long long, map< K, pair< V, timestamp_to_key_type::iterator > >::iterator >
= map< long long, map< K, pair< V, map< long long, map< K, pair< V, map< long long, map< K, pair < V ...

这不是前向声明的问题,您很容易尝试描述一种在自身上递归定义的类型。与以下没有什么不同:

struct A { B b; };
struct B { A a; };

解决这个问题的唯一方法是丢失一些静态类型信息。如您所说,您可以使用void*,或者您可以尝试定义自己的抽象类型擦除接口。您的选择。

【讨论】:

  • 这不是更像让每个结构都有指向另一个结构的指针吗?他有迭代器,而不是本身的类型,所以我认为问题不在于这个
  • 迭代器不一定是指针。它们可以是,而且经常是,类。彼得的分析是正确的。
  • @Dasaruga 我认为这是正确的。但在这种情况下,语言允许自引用(即struct A { A *a; } 的类型图将包含一个循环,但这很好)。但是,还有其他情况是不允许的。你不能有一个函数返回一个指向自身的指针或一个指向自身的参数,类型化。
  • @litb - 是的,我认为这是一个更好的比较:-)
【解决方案2】:

打破循环定义,其中一个包含 V,另一个包含迭代器:

typedef map<K, V> KVMap;
typedef map<long long, typename KVMap::iterator> TSMap;

如果您需要使用键来查找时间戳,并且该时间戳未存储在 V 中,那么您可以在 KVMap 中复制它:

typedef map<K, pair<V, long long> > KVMap;

从 K,您可以使用 KVMap::find,获取时间戳,然后使用 TSMap::find 并获取相应项目的句柄(例如,擦除它)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 2022-12-10
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多