【发布时间】:2012-07-07 19:16:27
【问题描述】:
上下文
我有一个自定义比较器,它接受另一个比较器并应用额外的检查:
template <template <typename> class Comparator, typename T>
struct SoftOrder : public std::binary_function<T, T, bool> {
bool operator()(const T lhs, const T rhs) const {
return Comparator<T>()(lhs, rhs) && AnotherCheck();
}
};
我有第二个接受比较器的类,例如:
template <template <typename> class Comparator>
class Processor { ... };
使用标准比较器(例如std::less)很容易实例化Processor,如下所示:
Processor<std::less> processor1;
Processor<std::greater> processor2;
然而,用SoftOrder 实例化并不容易,因为编译器正确地抱怨缺少第二个模板参数:
Processor<SoftOrder<std::less> > processor3; // <-- Fails to compile
当前解决方案
在发布此问题之前,我想出了一些解决方案。
第一个解决方案 - 大量派生类
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {};
template <typename T>
struct SoftOrderGreaterThan : public SoftOrder<std::greater, T> {};
此解决方案的主要缺点是每次需要新变体时都需要创建一个新结构,例如:
template <typename T>
struct SoftOrderLessThan : public SoftOrder<std::less, T> {}; // Never used after the next line.
Processor<SoftOrderLessThan> processor3;
第二种解决方案 - 一个非常具体的绑定类
template <template <typename> class Comparator>
struct BindToSoftOrder {
template <typename T>
struct type : public SoftOrder<Comparator, T> {};
};
这稍微好一点,因为我们不需要显式创建中间类:
Processor<BindToSoftOrder<std::less>::type> processor3;
缺点是需要专门针对这种情况的类的要求,不能通过使SoftOrder 成为BindToSoftOrder 上的模板参数来真正概括,因为这将使其成为标准不允许的template<template<template>>>。
第三种解决方案 - C++11 模板别名
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>;
比第一个选项更好,因为它不需要引入新的类,但仍然需要用这个额外的代码乱扔代码,这些额外的代码只用于传递给另一个模板类:
template <typename T>
using SoftOrderLessThan = SoftOrder<std::less, T>; // Never used again
Processor<SoftOrderLessThan> processor3;
最后,问题
是否有一种通用方法可以通过以下方式将我的自定义比较器绑定到特定比较器?
Processor<SomeCoolMetaTemplateBind<SoftOrder, std::less>::type> processor3;
我相信,如果所有模板参数都是简单类型,我可以执行类似Processor<boost::mpl::bind<SoftOrder, std::less> > 的操作,但是模板参数列表中存在模板类型会阻止这种情况发生。
理想的解决方案将涉及 C++03,但也很高兴听到 C++11 的解决方案。
如果不可能,我希望至少这个问题很有趣。
【问题讨论】:
-
Process期望模板模板参数有什么合法要求吗?您可以改用类型参数吗,客户端会使用例如Processor<std::less<T>>?然后SoftOrder也可以接受类型参数。这方面的一个例子是标准容器适配器,如std::stack——你传入std::stack<T, std::deque<T>>,而不是std::stack<T, std::deque>。模板模板参数通常使设计较少表现力或灵活。 -
@LucDanton 这是我正在考虑的事情,但这成为我和编译器之间的荣誉问题,我确信我最终会占上风。尽管正如 VaughnCato 在他的回答中指出的那样,我在上述解决方案 2 中关于标准的假设显然是老错误,所以我猜编译器笑到了最后……
标签: c++ templates boost boost-mpl