Skip to content

Commit 41b68dc

Browse files
authored
Simpler readme with references to existing docs
1 parent 80c81da commit 41b68dc

1 file changed

Lines changed: 18 additions & 164 deletions

File tree

README.md

Lines changed: 18 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -4,178 +4,32 @@
44
[![Standard](https://img.shields.io/badge/C%2B%2B-20%2B-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B20)
55
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
66

7-
An experimental C++ library and code generation tool for static structural
8-
subtyping (duck typing) with value semantics.
7+
We propose the addition of two class templates, `protocol<T, A>` and
8+
`protocol_view<T>`, to the C++ Standard Library. Both classes support
9+
structural-subtyping, `protocol` is owning, `protocol_view` is non-owning.
910

10-
## Overview
11+
See [DRAFT.md](DRAFT.md) for more details on design.
1112

12-
Polymorphic interfaces in C++ traditionally require explicit inheritance from an
13-
abstract base class. This nominal subtyping tightly couples independent
14-
components, makes it impossible to retroactively apply interfaces to third-party
15-
types, and typically forces reference semantics (e.g., `std::unique_ptr`).
16-
17-
Inspired by Python's `Protocol` (PEP 544), this repository explores bringing a
18-
similar paradigm to C++. By using AST parsing (via Clang) and code generation,
19-
the tool synthesizes type-erased wrappers that accept any type structurally
20-
conforming to an interface, without inheritance.
21-
22-
These protocols maintain deep-copy value semantics, strict `const`-propagation,
23-
and allocator awareness, consistent with the design of `jbcoe/value_types`
24-
(P3019).
13+
This repository contains both the ISO C++ proposal to add these new library
14+
types and a reference implementation. The reference implementation is currently
15+
reliant on a Python code-generation step as C++26 reflection is missing some of
16+
the features needed to generate code needed by these types at compile time.
2517

2618
## Standardization
2719

28-
As C++ reflection (P2996) matures and code injection is added in future
29-
standards (C++29+), the generation approach demonstrated here via `py_cppmodel`
30-
will be achievable natively within the language.
31-
32-
A draft proposal is available in `DRAFT.md`.
33-
34-
## Use
35-
36-
The interface is a plain struct with no `virtual` keywords, no `= 0`, and no base
37-
classes.
38-
39-
```cpp
40-
#pragma once
41-
#include <string>
42-
#include <vector>
43-
44-
namespace xyz {
45-
46-
struct B {
47-
void process(const std::string& input);
48-
std::vector<int> get_results() const;
49-
bool is_ready() const;
50-
};
51-
52-
} // namespace xyz
53-
```
54-
55-
Write your concrete type. It does not need to inherit from `xyz::B`; it only
56-
needs to structurally provide the methods defined in the interface.
57-
58-
```cpp
59-
namespace xyz {
60-
61-
class MyImplementation {
62-
std::vector<int> results_;
63-
bool ready_ = false;
64-
65-
public:
66-
// Structurally matches xyz::B
67-
void process(const std::string& input) {
68-
results_.push_back(input.length());
69-
ready_ = true;
70-
}
71-
std::vector<int> get_results() const { return results_; }
72-
bool is_ready() const { return ready_; }
73-
};
74-
75-
} // namespace xyz
76-
```
77-
78-
`xyz::protocol<xyz::B>` is an automatically generated type-erased wrapper. It
79-
copies deeply, propagates `const` correctly, and supports custom allocators.
80-
81-
```cpp
82-
#include "generated/protocol_B.h"
83-
84-
void run_pipeline(xyz::protocol<xyz::B> worker) {
85-
if (!worker.is_ready()) {
86-
worker.process("hello protocols");
87-
}
88-
89-
for (int result : worker.get_results()) {
90-
// ...
91-
}
92-
}
93-
94-
int main() {
95-
// Construct the protocol in-place with our implementation
96-
xyz::protocol<xyz::B> p(std::in_place_type<xyz::MyImplementation>);
97-
98-
run_pipeline(p); // Pass by value!
99-
return 0;
100-
}
101-
```
102-
103-
The generated wrapper uses C++20 concepts and `requires` clauses: any structural
104-
mismatch produces clear, pinpointed compile-time errors rather than deeply nested
105-
template instantiation failures.
106-
107-
```cpp
108-
class BadImplementation {
109-
public:
110-
void process(const std::string& input);
111-
// ERROR: Missing get_results()
112-
// ERROR: is_ready() is missing 'const'
113-
bool is_ready();
114-
};
115-
116-
// COMPILER ERROR:
117-
// constraints not satisfied
118-
// the required expression 'std::as_const(t).is_ready()' is invalid
119-
```
120-
121-
## `protocol_view`: Non-Owning Structural Subtyping
122-
123-
Alongside `protocol`, the code generator also produces a `protocol_view`
124-
specialization. While `protocol` manages the lifecycle of the underlying object
125-
(with deep-copy value semantics), `protocol_view` is a lightweight, non-owning
126-
reference, analogous to `std::string_view` or `std::span`, but for protocols.
127-
128-
```cpp
129-
// `view` observes the object without owning or copying it.
130-
void inspect(xyz::protocol_view<xyz::B> view) {
131-
if (view.is_ready()) {
132-
// ...
133-
}
134-
}
135-
136-
int main() {
137-
xyz::MyImplementation impl;
138-
139-
// Implicitly constructs a view over `impl` since it fulfills the structural requirements.
140-
inspect(impl);
141-
142-
xyz::protocol<xyz::B> p(std::in_place_type<xyz::MyImplementation>);
143-
// Implicitly constructs a view over `p` as the protocol itself satisfies the requirements.
144-
inspect(p);
145-
146-
return 0;
147-
}
148-
```
149-
150-
`protocol_view` provides non-owning, allocation-free structural dispatch at
151-
function boundaries, avoiding deep copies while dispatching through a
152-
lightweight indirection.
153-
154-
## Implementation Details and Benchmarks
155-
156-
The code generator generates a struct-of-function-pointers representing the vtable, managing type-erasure and dispatch via pointer indirection (manual vtables). This enforces constraints (value semantics, `const` correctness, and custom allocators) without requiring standard inheritance or compiler-generated virtual tables.
157-
158-
The library provides a `protocol_benchmark` target for measuring the performance of the protocol across allocations, copies, moves, and member function calls.
159-
160-
```bash
161-
# Build and run the benchmark
162-
./scripts/cmake.sh benchmark
163-
```
20+
The paper [P4148R2](https://wg21.link/P4148R2.pdf) (derived from
21+
[DRAFT.md](DRAFT.md)) was presented to the C++ Standard Library Incubator
22+
working group in Brno on June 11th 2026. The authors have been encouraged to
23+
continue work.
16424

16525
## Contributing and Development
16626

16727
For build instructions, testing, contributing guidelines, and a deeper look into
168-
the code generation architecture, see the [Developer Guide](CONTRIBUTING.md).
169-
170-
## References
171-
172-
- PEP 544: [Protocols: Structural subtyping (static duck
173-
typing)](https://peps.python.org/pep-0544/)
174-
175-
- P3019: [std::indirect and
176-
std::polymorphic](https://isocpp.org/files/papers/P3019R14.pdf)
28+
the code generation architecture, see [CONTRIBUTING.md](CONTRIBUTING.md).
17729

178-
- P2996: [Reflection for C++26](https://isocpp.org/files/papers/P2996R13.html)
30+
## GitHub codespaces
17931

180-
- py_cppmodel: [Python wrappers for clang's parsing of
181-
C++](https://github.com/jbcoe/py_cppmodel)
32+
Press `.` or visit [https://github.dev/jbcoe/cc-protocol] to open the project in
33+
an instant, cloud-based, development environment. We have defined a
34+
[devcontainer](.devcontainer/devcontainer.json) that will automatically install
35+
the dependencies required to build and test the project.

0 commit comments

Comments
 (0)