如果我有以下模板参数:
template <typename T_Key, typename T_Value, typename T_HashFunc,
typename T_ExtractKey, typename T_EqualKey, typename T_RehashClass, typename T_HashcodeClass>
class Hashtable { /* ... */ };
其中T_RehashClass
和T_HashcodeClass
是两个模板类,它们也接受T_Key、T_Value、T_HashFunc、T_ExtractKey和T_EqualKey
。我希望这些类从 Hashtable
的 typedef 列表中获取类型(Hashtable
中的所有模板参数类型都是类型定义的)。
请注意,T_RehashClass
和 T_HashcodeClass
也可以由用户创建(提供默认值),并且如果用户愿意,可以具有其他模板参数。
就目前情况而言,任何属于 T_RehashClass
的类都必须填写 T_Key、T_Value
等模板参数,我认为这是代码重复。我希望该类以某种方式了解 Hashtable
,以便它可以访问其 typedef 并通过创建自己的 typedef 自动推导 T_Key、T_Value
等类型。不幸的是,在这种情况下,我得到了循环依赖。
这类问题一般是如何解决的?
另请注意,我遵循 EASTL,其中 EASTL 使用多重继承来继承 T_RehashClass
和 T_HashnodeClass
,因此,Hashtable
具有更多功能模板参数。我想知道是否有解决方法(即不从两个策略继承并将它们作为模板参数,因为从策略继承会降低灵活性)。
我想到的一个解决方案是拥有一个模板结构,其中包含从 T_Key
到 T_EqualKey
的所有模板参数。 Hashtable
声明将是:
template <typename T_HashtableParams, typename T_RehashClass = default_rehash_class<T_HashtableParams>, typename T_HashcodeClass = default_hashnode_class<T_HashtableParams> >
class Hashtable { /* ... */ };
然后,T_RehashClass
和 T_HashcodeClass
可以采用默认值,从而消除代码重复。这种方法的问题是用户使用起来比较麻烦。
最佳答案
我不确定为哈希和重新哈希类指定不同的 T_Key 和 T_Value 类型是否非常有趣。如果我要解决这个问题,我会首先尝试为键/值设置策略。我的倾向是说也许应该有一个 ValuePolicy,而不是将其与 KeyPolicy 分组,但这既不在这里也不在那里。
namespace hash {
namespace detail {
template<
typename Key
, typename Value
, typename KeyGetter
, typename KeyComparator>
class KeyPolicy {
public:
typedef Key key_t;
typedef Value value_t;
typedef KeyGetter get_t;
typedef KeyComparator compare_t;
};
}} // hash detail
HashTable
无效,除非它具有与 rehast 相同的 KeyPolicy,所以不要给它一个。
namespace hash {
namespace detail {
template<typename RehashPolicy>
class HashTableImpl {
public:
typedef RehashPolicy rehash_p;
typedef typename rehash_p::key_policy_t::key_t key_t;
// typedef ...
};
// this doesn't have a specific name, its anything.
template<typename KeyPolicy>
class SomeRehashPolicy {
public:
typedef KeyPolicy key_policy_t;
};
}} // hash detail
显然,您可以在那里添加任何您想要的类型定义。如果我是代码审查中的坚持者,我可能会要求将 rehash_p
和 key_policy_t
等内容设为私有(private)。它们确实是实现细节。您试图保护的实际不变量是 key_t
等中的内容。
也许我超出了礼仪的合理范围,但我诚实的观点是,所有这些配置只对编写它的人感兴趣。不是你,也不是任何使用它的人。因此,我只会公开人们实际要使用的一两个 HashTable 配置。
namespace hash {
struct stub {}; // sorry, I'm lazy
template<typename Key, typename Value>
class HashTable {
private:
typedef typename detail::KeyPolicy<Key, Value, stub, stub> key_p;
typedef typename detail::SomeRehashPolicy<key_p> rehash_p;
typedef typename detail::HashTableImpl<rehash_p> impl_t;
public:
typedef typename impl_t::key_t key_t;
};
} // hash
int main(int argc, char ** argv) {
hash::HashTable<int, double> hash_table;
return 0;
}
很多细节没有明显填写,但你明白了。
关于c++ - 减少模板策略困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8845618/