diff --git a/.gitignore b/.gitignore index ea60d45..a8a3d14 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ cxx-bucket-vs*/ .vs/ .vscode/ .cache/ -generated/ out/ .gdb_history build-* diff --git a/generated/any_view.html b/generated/any_view.html new file mode 100644 index 0000000..4e0b27c --- /dev/null +++ b/generated/any_view.html @@ -0,0 +1,659 @@ + + + + + + + + `any_view` + + + + + + + +
+
+

any_view

+ + + + + + + + + + + + + + + + + + + + + +
Document #:PXXXXR0
Date:2024-05-27
Project:Programming Language C++
Audience: + SG9, LEWG
+
Reply-to: + Hui Xie
<>
+ S. Levent Yilmaz
<>
+ Louis Dionne
<>
+
+
+
+ +

1 Revision History

+

1.1 R0

+ +

2 Abstract

+

This paper proposes a new type-erased +view: +any_view.

+

3 Motivation and Examples

+

From C++20, a lot of views +have been introduced into the standard library. With these +views, it is quite easy to +create a range of objects. For example,

+
// in MyClass.hpp
+class MyClass{
+  std::unordered_map<Key, Widget> widgets_;
+public:
+  auto getWidgets () const {
+    return widgets_ | std::views::values
+                    | std::views::filter(myFilter);
+  }
+
+  // other members
+};
+

This works if one writes everything in the header. However, in +practice, in user’s non-templated code bases, headers usually contain +the declarations, and implementation details are hidden in the +implementation cpp files:

+
// in MyClass.hpp
+class MyClass{
+  std::unordered_map<Key, Widget> widgets_;
+public:
+  /* what should be the return type? */ getWidgets() const;
+
+  // other members
+};
+
+// in MyClass.cpp
+
+/* what should be the return type? */ MyClass::getWidgets() const {
+    return widgets_ | std::views::values
+                    | std::views::filter(myFilter);
+}
+

However, it is almost impossible to spell the correct type of the +return value. And in fact, to allow the flexibility of future changes, +we don’t actually want to spell that particular type of the +view. We need some type-erased +helper that can easily written in the header and can accept any concrete +type of view.

+

There is something very similar: Lambdas are extremely useful but one +cannot spell their types. When we need a type in the API boundary, we +often use the type-erased type +std::function.

+

Prior to C++20, that return type is often +std::vector<Widget>, which +enforces ownership. This also enforces implementations to make copy of +all the Widgets. On the other +hand, the caller may not care about the ownership at all and all it +wants is to iterate through them.

+

After C++20, that return type is sometimes +std::span<Widget>, which +explicitly says the caller does not want the ownership. However, one +major caveat is that this enforces contiguous memory. As a result, +implementations cannot return the +view pipelines as shown in the +example.

+

This paper proposes a new type-erased view +any_view so that the above +function’s return type can be spelled as any_view<const Widget&>.

+

4 Design

+

4.1 What Parameters can Users +Configure?

+

Let’s take std::function as +an example. Its interface seems extremely simple: the +operator() and users only need +to configure the return type and argument types. Well, it is a bit more +than that:

+ +

After answering all these questions we ended up with three types +now:

+ +

For any_view, it is much much +more complex than that:

+ +

We can easily get combinatorial explosion of types if we follow the +same approach of std::function. +So let’s look at the prior arts.

+

4.1.1 BOOST.Range +boost::ranges::any_range

+

Here is the type declaration

+
template<
+    class Value
+  , class Traversal
+  , class Reference
+  , class Difference
+  , class Buffer = any_iterator_default_buffer
+>
+class any_range;
+

It asks users to put +range_reference_t, +range_value_t and +range_difference_t. +Traversal is equivalent to +iterator_concept so it decides +the traversal category of the range. It does not need to configure +copyable, +borrowed_range and +common_range because all +BOOST.Range ranges are copyable, +borrowed_range and +common_range. +sized_range and +range_rvalue_reference_t are not +considered.

+

4.1.2 range-v3 +ranges::views::any_view

+

Here is the type declaration

+
template<typename Ref, category Cat = category::input>
+struct any_view;
+

Here Cat handles both the +traversal category and +sized_range. +Ref is the +range_reference_t. It does not +allow users to configure the +range_value_t, +range_difference_t, +borrowed_range and +common_range. +copyable is mandatory in +range-v3.

+

5 Implementation Experience

+

6 Wording

+

6.1 Feature Test Macro

+

```

+ +
+
+ +