C++ 概念需要一个以 OutputIterator 作为参数的成员函数

Chr*_*Ott 5 c++ c++-concepts c++20

我正在玩概念并遇到障碍。或者也许只是我的思想被阻塞了。

我想创建一个缓冲“批量可读”数据源的类。这样的数据源应该有一个成员函数,它接受一个 OutputIterator 并具有如下签名:

template<typename It>
size_t read(It firstItem, size_t max)
Run Code Online (Sandbox Code Playgroud)

我的想法是定义一个BulkReadable类似于以下内容的概念:

template<typename Source>
concept bool BulkReadable = 
    requires(Source s, Iter out, size_t max) {
        {s.read(out, max)} -> size_t;
    };
Run Code Online (Sandbox Code Playgroud)

我在指定Iter. 我可以向模板参数列表中添加另一个类型名,但是想要使用该概念的 Buffer 类需要指定该参数的类型。

我想如何使用这个概念的理想方式是:

template<BulkReadable Source>
class Buffer {
  public: 
    Source& input:
    Buffer(Source& input) : input(input){}
    ...     
Run Code Online (Sandbox Code Playgroud)

这种方法甚至可行吗?如果是,如果我不想/可以指定类型,我如何要求模板化方法签名?

Nic*_*las 5

这是提出错误概念问题的一个常见问题,您试图像使用基类接口一样使用它们。对于基类,您可以声明派生类要实现的确切、特定的函数。您希望用户准确地实现您所说的必须执行的功能。

通过概念,您可以从另一个方向处理问题:您想要创建什么用途?

在代码中的某个时刻,您有一些对象、一些迭代器和一个大小。您将获取该对象,通过向其传递迭代器和大小来调用函数,并且您期望得到某种类型的响应。而这个过程是有一定意义的。

那么就是你的概念。这个概念至少基于两个参数:对象的类型和迭代器类型。这就是你应该创建的。

如果你有这个BulkReadable约束,那么你必须有一些接口对其进行约束。将要调用的接口read。要调用read,该接口必须有一个迭代器。

所以这里有一些选择:

  1. 用户(直接或间接)为接口指定迭代器类型。如果是这种情况,那么您只需在函数的BulkReadable约束中使用该类型即可。如果迭代器类型基于一组复杂的参数操作,那么您必须进行一些计算来计算迭代器类型。

  2. 迭代器是静态确定的。然后只需在约束中使用已知的迭代器类型即可。

重点是,在您尝试调用 时read,您知道迭代器类型是什么。因此,您可以使用该类型来约束事物。因此,你的概念不是真正的BulkReadable,而是BulkReadableFrom

简而言之,您不应该希望限制类型能够采用任何类型(或某些约束内的任何类型)。根据您要使用它们的实际类型检查约束,最好是在它们变得相关的时候。