请不要把我的“后期绑定”弄错,我不是指运行时通常的后期绑定,我的意思是别的,找不到更好的词来形容它:
考虑我正在为某些需要将这些值与比较器比较的Containor
值类型的容器(或类似)数据结构工作,所以我的第一个模板看起来像这样V
template<typename Val, typename Comp = std::less<Val>>
struct Containor{};
现在,我的Containor
结构在内部使用了另一个容器。要使用的容器也应该可以通过模板参数进行配置,假设默认是std::set
. 所以我的下一个版本Containor
看起来像这样:
template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set<Val,Comp>>
struct Containor{};
这是代码开始闻到恕我直言的地方。只要用户对内部容器的默认实现感到满意,一切都很好。但是,假设他想使用新的 google btree set 实现btree::btree_set
而不是std::set
. 然后他必须像这样实例化模板:
typedef Containor<int,std::less<int>,btree::btree_set<int,std::less<int>> MyContainor;
^^^^^^^^^^^^^^^^^^^
我已经强调了我的问题所在的部分。客户端代码必须使用正确的参数来实例化 btree_set。老实说,这很糟糕,因为Containor
该类总是需要一组与其自己的前两个模板参数完全相同的类型和比较器。客户可以 - 不小心 - 在此处插入其他类型!此外,客户有选择正确参数的负担。在这种情况下,这可能很容易,但如果内部容器必须是一组值类型和其他类型的对,那就很难了。然后客户端更难获得正确的内部集的类型参数。
所以我想要的是一种客户端代码只提交原始模板并在Containor
内部用正确的参数实例化它的方式,即类似的东西:
template<typename Val, typename Comp = std::less<Val>, typename Cont = std::set >
struct Containor{
typedef Cont<Val,Comp> innerSet;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ container instanciates the inner containor
};
typedef Containor<int,std::less<int>,btree::btree_set> MyContainor;
// ^^^^^^^^^^^^^^^^
// client only hands in raw template
当然,这不是有效的 C++!
所以我想了一些办法来解决这个问题。我能想到的唯一解决方案是为我想要使用的所有数据结构编写“绑定器类”,如下所示:
struct btree_set_binder{
template<typename V, typename C = std::less<V>>
struct bind{
typedef btree::btree_set<V,C> type;
}
};
现在我可以Containor
用一套活页夹来定义我的
template<typename Val, typename Comp = std::less<Val>, typename ContBinder = btree_set_binder >
struct Containor{
typedef btree_set_binder::bind<Val,Comp>::type innerSet;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ works like a charm
};
现在,用户必须只提供所需的 binder 类,Containor
然后用正确的参数实例化它。所以这些 binder 类对我来说没问题,但是为所有容器编写 binder 类相当麻烦。那么在 C++11 中是否有更好或更简单的方法来“晚”绑定模板参数,即在另一个将原始模板作为参数检索的模板内。