Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
394 views
in Technique[技术] by (71.8m points)

c++20 - C++ Concept that requires a member function with an OutputIterator as parameter

I am playing with concepts and hit a roadblock. Or maybe it is just my mind that is blocked.

I want to create a class that buffers a "bulk-readable" data source. Such a datasource should have a member function that accepts an OutputIterator and has a signature like:

template<typename It>
size_t read(It firstItem, size_t max)

My idea was to define a BulkReadable concept similar to:

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

I am having trouble specifying Iter. I could add another typename to the template parameter list, but then the Buffer class that wants to use the concept would need to specify the type of that parameter.

The ideal way how I would like to use the concept is:

template<BulkReadable Source>
class Buffer {
  public: 
    Source& input:
    Buffer(Source& input) : input(input){}
    ...     

Is this approach even viable? If yes, how can I require a templated method signature if I do not want/can specify the type?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is a common problem of asking the wrong question of a concept, where you're trying to use them like you would a base class interface. With base classes, you're declaring the exact, specific functions that the derived classes are to implement. You want the user to implement exactly the function you say they must.

With concepts, you approach the issue from the other direction: what usage are you trying to create?

At some point in your code, you have some object, some iterator, and a size. And you're going to take that object, call a function by passing it the iterator and the size, and you expect a response back of a certain type. And this process has some meaning.

Then that is your concept. It's a concept that is based on at least 2 parameters: the type of the object and the iterator type. So that's what you should create.

If you have this BulkReadable constraint, then you must have some interface constrained on it. An interface that's going to call read. To call read, that interface must have an iterator.

So here are the options:

  1. The interface is given an iterator type (directly or indirectly) by the user. If that's the case, then you just use that type in the function's BulkReadable constraint. If the iterator type is based on a complex set of operations on parameters, then you'll have to do some computations to compute the iterator type.

  2. The iterator is statically determined. Then just use the known iterator type in the constraint.

The point being that, at the point where you're going to try to call read, you know what the iterator type is. And therefore, you can constrain things using that type. Your concept therefore is not really BulkReadable, but BulkReadableFrom.

In short, you shouldn't want to constrain a type on being able to take any type (or any type within some constraints). Check constraints against the actual types you're going to use them with, preferably at the point where they become relevant.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...