c++ - 可选地发布基于可变模板参数的方法

标签 c++ template-meta-programming

前言

假设我有一个模板: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_tunisgned long long 时它可能更大),其中实际缓冲区(大小例如 4096B)在该虚拟内存中创建一个窗口

Link to my other related question - option pack helper 专为此模板设计。

(请注意,可能还有许多其他功能可以独立组合,例如 opt::rqueue_listener 可用于报告各种事件)。

问题

我已经设法创建了具有所有可能功能的模板,其中一些方法在未选择功​​能时是虚拟(例如,start() 返回零,stop() 在这种情况下与 size() 相同) ,但如果未选择该功能,我想以某种方式隐藏这些方法。 有什么想法吗?

(如果不包括 set_listener(void*),另一个示例将是虚拟 opt::rqueue_listener - 该选项可以与任何其他选项组合。)

编辑:想象一下,例如using off_t = conditional_t<something,the_type,void>private: off_t start_() 。我想要的是:

  1. 如果 public: off_t start() 不是 start_(),则让 off_t 调用 void
  2. 如果 start() 无效(或满足某些条件),则没有方法 off_t。或者,如果我尝试调用它,则为 static_assert

我的尝试

我正在考虑将该类与 extenders 合并,后者将通过将自身 ( *this ) 转换为实际类 ( rqueue<...>& ) 并将调用重定向到那里(到私有(private)方法,其中 < em>extender 成为 friend )。我创建了另一个 template<class... Bases> class merge 助手,它可以继承任何选定的类,同时忽略任何传递的 void。它有效,但解决方案非常丑陋,我不喜欢它。

我想到的另一个可能的解决方案是创建一些基本实现(作为不同的模板,可能隐藏在某些 namespace detail 中)并使用一系列模板特化,这些模板将根据选项发布方法。问题是组合的数量正在快速增长,并且 friend 可能存在另一个问题 - 让类访问记录的私有(private)方法(传递给模板的第一个参数)。

我的 SFINAE 和 static_assert 尝试经常以编译器错误结束,提示模板中不允许方法特化(或部分特化)或者 static_assert 在不应该被触发时被触发。我希望有一些不错的解决方案。期待看到它:)

最佳答案

下面的代码是我在 Piotr S. 的提示下尝试的:
(想象一下 在该 header 中使用命名空间 std,尽管它有点不同。)

#include "basics.hpp"
using namespace firda;

template<class Offset = void> struct helper {
    Offset start_() const { return 0; }
};
template<> struct helper<void> {
    void start_() const {}
};

template<class Offset = void> class rqueue
  : private helper<Offset> {
public:
    Offset start() const {
        static_assert(!is_same<Offset,void>::value, "!!");
        return this->helper<Offset>::start_();
    }
};

int main() {
    rqueue<> one;
    rqueue<uint> two;
    cout << two.start();
//  one.start(); -- assert triggered
}

我在实际代码中遇到了类似 static_assert 的一些问题,但不记得为什么编译器在基本版本中触发了它……可能是我错误地在不应该的地方调用它。我认为有一个 start_() 用于内部使用(如果不使用则伪造它)并且有一个 public: start() 与断言(并确保不要在模板中调用它)解决了问题。我会等一会儿(如果有的话,我很乐意接受不同的答案)。

关于c++ - 可选地发布基于可变模板参数的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26336819/

相关文章:

c++ - 在二维 vector C++ 中生成随机数

c++ - GLFW 2 升级到 3 导致顶点数组生成崩溃

c# - 无法从 C# 应用程序调用简单的自定义 Dll 导入

c++ - 重载运算符->

c++ - 如何在具有不同模板参数的 C++ 模板之间隐式转换

c++ - 条件默认构造函数可以在 GCC 中编译,但不能在 MSVC 中编译

c++ - 为什么在分解 std::tuple 时需要 std::integral_constant?

c++ - C++ 到 Delphi 的转换(简单)

c++ - 模板特化,其中参数是用于元编程的非类型参数化模板

C++。当类T需要类型A模板参数时,如何为类A定义类型T的模板参数?