减少模板策略杂波
如果我有下面的模板参数:减少模板策略杂波
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 and T_EqualKey
以及两个模板类。我希望这些类可以从Hashtable
的typedef列表中获取类型(Hashtable
中的所有模板参数类型均为类型定义)。
请注意,T_RehashClass
和T_HashcodeClass
也可以由用户创建(默认提供),如果用户希望可以有其他模板参数。
现在,任何类T_RehashClass
必须有T_Key, T_Value
等模板参数填写,我认为这是代码重复。我希望该课程知道Hashtable
,以便它可以通过创建自己的typedef自动访问其typedefs并自动推断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
可以再取这将消除代码重复的默认值。这种方法的问题是用户使用起来更麻烦。
参见例如,现代C++设计(第1.5.1节:使用模板参数实现策略)。这个想法是让T_RehashClass和T_HashcodeClass成为模板参数。这些类将T_Key,T_Value和其他任何参数作为自己的参数。为了避免重新输入,您可以继承这些模板所需的实例。
template <
typename T_Key,
typename T_Value,
typename T_HashFunc,
typename T_ExtractKey,
typename T_EqualKey,
template<typename, typename /*, more params */> class T_RehashClass,
template<typename, typename /*, more params */> class T_HashcodeClass
> class Hashtable
:
public T_RehashClass<T_Key, T_Value /*, more params */>,
public T_HashcodeClass<T_Key, T_Value /*, more params */>
{ /* ... */ };
注意:你真正需要的“类”,而不是“类型名称”中T_RehashClass和T_HashcodeClass的前面,因为他们是模板的名称,而不是模板类型!
感谢。这实际上与EASTL正在做的非常接近。我读现代C++设计将重新您指出我同意的配置有趣的是只有谁写它的人的部分(+1) – Samaursa 2012-01-18 02:14:50
我不确定为hash和rehash类指定不同的T_Key和T_Value类型是非常有趣的。如果我正在解决这个问题,我会尝试为key/val首先设置一个策略。我的倾向是说可能应该有一个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
是无效的,除非它具有相同的KeyPolicy作为rehast等,所以不要给它一个。
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
显然你可以添加你想要的任何typedefs。如果我在代码审查是一个坚持己见的人我可能会问的东西像rehash_p
和key_policy_t
是私有的。他们真的是实施细节。你试图保护的实际不变是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;
}
很多细节未填写很明显,但你的想法。
。因为我正在编写自己的Hashtable,所以我对它也很感兴趣:)但是我同意,它增加了最终用户的混乱,并可能使他们感到困惑(可能是我在路上)。参考任何未来的SOer,在上述实现中,除非使用基类优化,否则“细节”类将占用额外的空间。 +1进行详细解释。 – Samaursa 2012-01-18 02:39:49
@Samaursa最终用户不必详细处理任何事情,除非他们想要。您可以将其隐藏在完全不同的标题中,以便最终用户不必知道。基类是“优化”任何东西,它增加了额外的虚拟呼叫。如果这对你更有意义,那么维护起来就更简单了。我会说这很有价值。 – 2012-01-18 15:32:06
在这种情况下,'Hashtable'是用户不会直接使用的东西。他们将使用一个关联容器,比如'hash_map',它将使用'Hashtable'作为其逻辑。所以基本上,所有这些灵活性都是为了图书馆作者(现在我)。所以是的,我将主要“隐藏”细节,并像你指出的那样公开一个'hash_map'类。至于基类优化,我没有仔细阅读。你正在声明'typedef's,我认为那里有一个变量。 – Samaursa 2012-01-18 16:07:06
我很好奇你为什么需要这么多的灵活性,允许用户指定表会变得如何改头换面......这真的好像YAGNI应该在踢 - 你想解决什么问题需要这么多的定制? – Yuushi 2012-01-13 03:47:02
'T_ExtractKey'和'T_EqualKey'是多余的(你可以提取关键的平等的测试,没有必要为一个独立的仿函数的一部分),以及'T_HashFunc'和'T_HashcodeClass'似乎也。 – 2012-01-13 03:48:40
@CatPlusPlus:那么,在这个实现,但它有节点存储hashkey与否的选项。 'T_HashcodeClass'有两个不同的实现,一个假设hashkey存储,另一个不存在。至于其他人,我也不完全确定,但EASTL拥有它。现在我知道这是不是包括它的理由,但我想笔者知道的比我多,我最终会明白(以下简称“最终understand'部分做了其他容器发生在我身上,而下面EASTL) – Samaursa 2012-01-13 03:55:21