【发布时间】:2014-10-13 09:34:04
【问题描述】:
前言
假设我有一个模板:template<class... Opts> class rqueue,它可以通过传递给参数列表的标签(特殊选项结构)选择各种功能,例如
rqueue<trace_record, opt::fixed_size<>> trace;
rqueue<trace_record::flat, opt::fixed_size<>, opt::virtual_offset<>> info;
第一个版本 (trace) 是用于写入跟踪记录的记录队列(opt::fixed_size 将其大小限制为 4096B)。第二个版本 (info) 将从第一个版本中填充(通过某个线程,它将重写记录并转换为 flat 表示),但重要的是 opt::virtual_offset<> 添加这些方法:
off_t start(); // virtual offset of oldest record
off_t stop(); // virtual offset of future record (when next gets written)
以及基于这个始终在增长(每条记录)的虚拟偏移量的各种其他功能(offset_to_iterator()),它模拟大小的虚拟内存,例如4 GB(当unsigned 用作偏移量时,使用size_t 或unisgned long long 可能会更大),其中实际缓冲区(大小例如4096B)在该虚拟内存中创建一个窗口记忆。
Link to my other related question - option pack helper 专门为此模板设计的。
(请注意,可能还有许多其他可以独立组合的功能,例如可用于报告各种事件的opt::rqueue_listener)。
问题
我已经设法创建了具有所有可能功能的模板,其中某些方法在未选择该功能时是 dummy (例如,start() 返回零,stop() 与 @ 相同987654336@ 在这种情况下),但如果未选择该功能,我想以某种方式隐藏这些方法。 有什么想法吗?
(如果不包含 opt::rqueue_listener,则另一个示例是虚拟 set_listener(void*) - 该选项可以与任何其他选项结合使用。)
编辑:想象一下,例如using off_t = conditional_t<something,the_type,void> 和 private: off_t start_()。我想要的是:
- 如果
off_t不是void,则让public: off_t start()调用start_() - 如果
off_t无效(或满足某些条件),则没有方法start()。或者一些static_assert,如果我尝试调用它。
我的尝试
我正在考虑将类与 extenders 合并,这将通过将自身 (*this) 转换为真实类 (rqueue<...>&) 并将调用重定向到那里(到私有方法)来发布函数, extender 成为朋友)。我创建了另一个 template<class... Bases> class merge 助手,它可以继承任何选择的类,同时忽略任何传递的 void。它有效,但解决方案很丑陋,我不喜欢它。
我想到的另一个可能的解决方案是创建一些基本实现(作为不同的模板,可能隐藏在某些 namespace detail 中)并使用一系列模板专业化,这些模板将基于选项发布方法。问题是组合的数量正在迅速增长,friend 可能还有另一个问题 - 让该类访问记录的私有方法(传递给模板的第一个参数)。
我的 SFINAE 和 static_assert 尝试经常以编译器错误结束,抱怨模板(或部分特化)中不允许方法特化,或者 static_assert 在不应该被触发时被触发。我希望有一些不错的解决方案。期待看到它:)
【问题讨论】:
-
是 opt::features 总是带有一个模板类型参数的模板吗?
-
每个特征都是一个结构(可能是带有其他参数的模板,但作为类传递,而不是作为模板传递)。我不认为那是那么重要。有关详细信息,请参阅链接的问题。
-
例如
fill_empty接受两个参数 - 类型和值:template <class T, T V> struct fill_empty: tag::fill_empty { typedef T type; static constexpr T value = V; }; -
好吧,也许我不明白你的目标是什么,简而言之:你总是实现
start()成员函数,但是当你的类继承自virtual_offset<>时,你希望它调用virtual_offset<>::start(),否则无法访问? -
为什么
static_assert(!std::is_same<off_t, void>::value, "!");在公共start()成员函数中不是一个选项?
标签: c++ template-meta-programming