请不要误解我的“后期绑定(bind)”,我不是指通常的运行时后期绑定(bind),我指的是别的意思,找不到更好的词来形容它:
考虑到我正在为一些需要将这些值与比较器进行比较的值类型 V
处理容器(或类似的)数据结构 Containor
,所以我的第一个模板看起来像这样
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 集实现 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++!
于是我想办法解决这个问题。我能想到的唯一解决方案是为我想使用的所有数据结构编写“绑定(bind)器类”,如下所示:
struct btree_set_binder{
template<typename V, typename C = std::less<V>>
struct bind{
typedef btree::btree_set<V,C> type;
}
};
现在我可以用一个 set binder 定义我的 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
};
现在,用户只需提供所需的绑定(bind)器类,Containor
将使用正确的参数实例化它。所以这些 Binder 类对我来说没问题,但是为所有容器编写 Binder 类是一件很麻烦的事情。那么有没有更好或更简单的方法来在 C++11 中“延迟”绑定(bind)模板参数,即在另一个模板中检索原始模板作为参数。
最佳答案
也许可以制作自己的比较器特征。
// Comparator trait primary template
template <typename T> stuct MyComparator
{
typedef typename T::key_compare type;
};
// Comparator trait non-standard usage example
template <typename U, typename V, int N>
struct MyComparator<WeirdContainer<U, V, N>>
{
typedef std::greater<V> type;
};
template <typename T, typename Cont = std::set<T>>
struct MyAdaptor
{
typedef typename MyComparator<Cont>::type comparator_type;
typedef T value_type;
// ...
};
我已将您的“容器”重命名为“MyAdaptor”,因为这种构造通常称为“适配器”类。
用法:
MyAdaptor<int> a; // uses std::set<int> and std::less<int>
MyAdaptor<double, WeirdContainer<bool, double, 27>> b;
更新:根据讨论,您甚至可以完全删除外部类型参数:
template <typename Cont> struct MyBetterAdaptor
{
typedef MyAdaptorTraits<Cont>::value_type value_type;
typedef MyAdaptorTraits<Cont>::pred_type pred_type;
// ...
};
像这样使用:
MyBetterAdaptor<std::set<int>> c; // value type "int", predicate "std::less<int>"
编写 MyAdaptorTraits
模板留作练习。
关于C++11 "late binding"模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15029611/