【发布时间】:2019-11-01 15:02:35
【问题描述】:
我正在编写一个 I/O 库,用户需要在其中提供要读取或写入的内存块。让我的图书馆接受span<T> 似乎是最自然的选择,因为:
- 它不会将容器选择强加给用户。他们可以使用原始指针、
std::vector或任何其他具有连续存储的容器。 - 由于我知道缓冲区的大小,因此我可以确保内存访问是安全的。
不幸的是,在 Boost、GSL 和标准库(从 C++20 开始)中存在 span<T> 的竞争实现。这些实现的接口是兼容的,从用户的角度来看,他们使用哪一个并不重要。
如何编码我的 I/O 函数,以便它们与 span 的任何各种实现一起使用?
目前我能想到的唯一方法是包含我自己的span 实现,它可以通过::element_type、.data() 和.size() 的任何内容隐式构造。
重要的是仍然支持来自容器的隐式转换,以便用户可以简单地传递std::vector。例如:
void read_data(span<float> data);
std::vector<float> foo(1024);
read_data(foo);
【问题讨论】:
-
有一个“config.h”来选择使用哪个是可能的。
-
要么有一个构建系统或预处理器标志来选择使用哪一个,要么让你的所有函数接受
span模板并接受任何span-like。 -
@MilesBudnek:
template的问题是不再有转换为span以获得相同/预期的跨度接口;我的意思是template <typename Span> void read_data(Span span) { span.begin(); /*..*/ }不会接受float data[42]而void read_data(std::span<float> span) { span.begin(); /*..*/ }会。并强制用户显式调用read_data(std::span<float>(data)是可悲的。 -
@Jarod42 使用
config.h意味着在库构建时做出选择。这将阻止库的不同用户(在同一系统上)使用他们首选的跨度实现。 -
@marack 不是它将所有不同的
spans 调整为一个内部使用的library::span