Skip to content

Commit 7696ce1

Browse files
Adding a few slides to discuss the containers problem and how concepts make our life easier
1 parent 97a9f0d commit 7696ce1

File tree

1 file changed

+71
-13
lines changed

1 file changed

+71
-13
lines changed

cppcon2025/cppcon_2025_slides.md

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ err = json.Unmarshal([]byte(jsonStr), &deserializedPlayer)
310310

311311
# Go reflection
312312

313-
- Runtime reflection only
313+
- Runtime reflection only
314314

315315
```Go
316316
typ := reflect.TypeOf(obj)
@@ -367,7 +367,7 @@ let player: Player = serde_json::from_str(&json_str)?;
367367
# Rust reflection
368368

369369

370-
- Rust does not have ANY introspection.
370+
- Rust does not have ANY introspection.
371371
- You cannot enumerate the methods of a struct. Either at runtime or at compile-time.
372372
- Rust relies on annotation (serde) followed by re-parsing of the code.
373373

@@ -406,7 +406,7 @@ Player player = simdjson::from<Player>(json_str);
406406

407407
**"How can compile-time reflection handle runtime JSON data?"**
408408

409-
The answer: Reflection operates on **types and structure**, not runtime values.
409+
The answer: Reflection operates on **types and structure**, not runtime values.
410410

411411
It generates regular C++ code at compile time that handles your runtime data.
412412

@@ -498,7 +498,7 @@ struct Player {
498498

499499
// RUNTIME: The generated code processes actual JSON data
500500
std::string json = R"({"username":"Alice","level":42,"health":100.0})";
501-
Player p = simdjson::from<Player>(json);
501+
Player p = simdjson::from<Player>(json);
502502
// Runtime values flow through compile-time generated code
503503
```
504504
@@ -655,23 +655,81 @@ Just simdjson leveraging C++26 reflection.
655655
656656
---
657657
658-
# Supporting Standard Containers
658+
# The Container Challenge
659659
660-
Through concepts and template specialization, we support:
660+
We can say that serializing/parsing the basic types and custom classes/structs is pretty much effortless.
661661
662-
- `std::vector<T>`, `std::array<T, N>`
663-
- `std::map<K, V>`, `std::unordered_map<K, V>`
664-
- `std::optional<T>`
665-
- `std::variant<Types...>`
666-
- And many more...
662+
How do we automatically serialize ALL these different containers?
667663
668-
All work seamlessly with reflection!
664+
- `std::vector<T>`, `std::list<T>`, `std::deque<T>`
665+
- `std::map<K,V>`, `std::unordered_map<K,V>`
666+
- `std::set<T>`, `std::array<T,N>`
667+
- Custom containers from libraries
668+
- **Future containers not yet invented**
669+
670+
---
671+
672+
# The Naive Approach: Without Concepts
673+
674+
Without concepts, you'd need a separate function for EACH container type:
675+
676+
```cpp
677+
// The OLD way - repetitive and error-prone! 😱
678+
void serialize(string_builder& b, const std::vector<T>& v) { /* ... */ }
679+
void serialize(string_builder& b, const std::list<T>& v) { /* ... */ }
680+
void serialize(string_builder& b, const std::deque<T>& v) { /* ... */ }
681+
void serialize(string_builder& b, const std::set<T>& v) { /* ... */ }
682+
// ... 20+ more overloads for each container type!
683+
```
684+
685+
**Problem**: New container type? Write more boilerplate!
686+
687+
---
688+
689+
# The Solution: Concepts as Pattern Matching
690+
691+
Concepts let us say: **"If it walks like a duck and quacks like a duck..."**
692+
693+
```cpp
694+
// The NEW way - one function handles ALL array-like containers!
695+
template<typename T>
696+
requires(has_size_and_subscript<T>) // "If it has .size() and operator[]"
697+
void serialize(string_builder& b, const T& container) {
698+
b.append('[');
699+
for (size_t i = 0; i < container.size(); ++i) {
700+
serialize(b, container[i]);
701+
}
702+
b.append(']');
703+
}
704+
```
705+
706+
✅ Works with `vector`, `array`, `deque`, custom containers...
707+
708+
---
709+
710+
# Concepts + Reflection = Automatic Support
711+
712+
When you write:
713+
```cpp
714+
struct GameData {
715+
std::vector<int> scores; // Array-like → [1,2,3]
716+
std::map<string, Player> players; // Map-like → {"Alice": {...}}
717+
MyCustomContainer<Item> items; // Your container → Just works!
718+
};
719+
```
720+
721+
The magic:
722+
1. **Reflection** discovers your struct's fields
723+
2. **Concepts** match container behavior to serialization strategy
724+
3. **Result**: ALL containers work automatically - standard, custom, or future!
725+
726+
**Write once, works everywhere™**
669727

670728
---
671729

672730
# Conclusion
673731

674-
## C++26 Reflection + simdjson =
732+
## C++26 Reflection + simdjson =
675733

676734
-**Zero boilerplate**
677735
-**Compile-time safety**

0 commit comments

Comments
 (0)