Skip to content

Commit 681c19e

Browse files
committed
tones of up
1 parent d389945 commit 681c19e

23 files changed

+1992
-1613
lines changed

CMakeLists.txt

Lines changed: 236 additions & 138 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ This change ensures that VSCode uses the "Ninja Multi-Config" generator by defau
174174
- [lists](src/lists.cpp)
175175
- [C arrays, std::array, span](docs/array_span.md)
176176
- [set, map, pair, tuple, tie, unordered_map, multimap, unordered_set, multiset](docs/set_map_pair_tuple.md)
177-
- [stack, queue, priority_queue, deque](docs/stack_queue_priority_queue_deque.md)
177+
- [Queue, Priority queue, deque](docs/stack_queue_priority_queue_deque.md)
178+
- [Stack](docs/stack.md)
178179
- [Const, Constexpr and Mutable](docs/const_constexpr_mutable.md)
179180
- [Immutable Objects](docs/immutable_objects.md)
180181
- [Data Types, Numerical Limits, Machine Epsilon, Precision, std::nan](docs/primitive_data_types_numerical_limits_machine_epsilon_precision.md)
@@ -246,8 +247,9 @@ This change ensures that VSCode uses the "Ninja Multi-Config" generator by defau
246247
- [Cast Base Class to Derived/ Derived to Base](src/class/cast_Base_to_Derived_to_Base.cpp)
247248
- [Class Forward Declaration](docs/class_forward_declaration.md)
248249
- [Class Constructor Initializationlist](src/class/constructor_initialization_list.cpp)
249-
- [Class Constructor Aggregate/ Copy/ Default/ Direct/ Value/ Uniform/ Zero Initialization, Initializer List](docs/aggregate-copy-default-direct-value-zero_initialization.md)
250+
- [Class Constructor Aggregate/ Copy/ Default/ Direct/ Value/ Uniform/ Zero Initialization, Initializer List](docs/initialization.md)
250251
- [Copy Constructor, Copy Assignment, Move Constructor, Assignment](docs/copy_constructor_move_constructor.md)
252+
- [Shallow Copy, Deep CCopy](docs/shallow_copy_deep_copy.md)
251253
- [Cyclic (Circular) Dependency](docs/circular_dependencies.md)
252254
- [Default(=default), Deleted (=delete) Constructors](docs/default_constructors_=default_0_delete.md)
253255
- [Diamond Problem Virtual Inheritance](src/class/diamond_problem_virtual_inheritance.cpp)
@@ -329,10 +331,15 @@ This change ensures that VSCode uses the "Ninja Multi-Config" generator by defau
329331
- [JSON](docs/json.md)
330332
- [XML](docs/tinyxml2.md)
331333

332-
## [REST API and Microservices with C++](#)
334+
## [REST API, Microservices, and Communication Libraries with C++](#)
333335

334336
- [Monolithic Architecture vs REST API and Microservices](docs/microservices/REST_API_microservices.md)
335-
- [gRPC](docs/microservices/grpc.md)
337+
- [REST APIs / Webhooks with cURL (libcurl)](https://github.com/curl/curl)
338+
- [gRPC C++ (official)](https://github.com/grpc/grpc)
339+
- [WebSockets with IXWebSocket](https://github.com/machinezone/IXWebSocket)
340+
- [WebRTC with libdatachannel](https://github.com/paullouisageneau/libdatachannel)
341+
- [GraphQL with cppgraphqlgen](https://github.com/microsoft/cppgraphqlgen)
342+
- [XML SOAP with tinyxml2 + cURL](docs/microservices/xml_soap.md)
336343
- [REST API with crow](docs/microservices/REST_API_with_crow.md)
337344
- [mocking APIs with Mockoon](docs/microservices/mockoon.md)
338345
- [Test API with Postman](docs/microservices/test_API_with_postman.md)
@@ -399,6 +406,7 @@ This change ensures that VSCode uses the "Ninja Multi-Config" generator by defau
399406
- [High-Performance Computing (HPC) Patterns](docs/system_design/hpc_patterns.md)
400407
- [Serialization and Deserialization (Protobuf, FlatBuffers)](docs/system_design/serialization.md)
401408
- [Error Handling Strategies and Fault Tolerance](docs/system_design/error_handling_strategies.md)
409+
- [Design a reusable library](docs/system_design/design_a_reusable_library.md)
402410

403411
## [VSCode](#)
404412

docs/SFINAE.md

Lines changed: 168 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,192 @@
1-
# SFINAE
2-
SFINAE, which stands for "Substitution Failure Is Not An Error," is a concept in C++ template programming. It's a rule that applies during the template instantiation process. The idea is that if a substitution of template parameters into a template results in an invalid code, this is not in itself an error. Instead, the invalid template is simply discarded from the set of potential templates to use.
1+
## 1. What problem are we solving?
32

4-
This concept is particularly useful for creating template specializations that are only valid for certain types or conditions, enabling more flexible and powerful template designs.
3+
We want this behavior:
54

6-
### Basic Example of SFINAE
5+
```cpp
6+
divide(10, 2); // OK
7+
divide(10.0, 2.0); // OK
8+
divide(std::string{}, std::string{}); // ❌ not allowed
9+
```
10+
11+
But **C++ templates are instantiated only when used**, so we need a way to:
12+
13+
* **Enable** a function for some types
14+
* **Disable** it for others
15+
* **Without producing a compilation error**
16+
17+
This is exactly what **SFINAE** does.
18+
19+
---
20+
21+
## 2. What is SFINAE?
22+
23+
**SFINAE** means:
24+
25+
> **Substitution Failure Is Not An Error**
26+
27+
When the compiler tries to substitute a template type, and that substitution **fails**, the compiler:
28+
29+
* ❌ does **not** error
30+
* ✅ simply **removes that function from overload resolution**
31+
32+
So the function **silently disappears**.
33+
34+
---
35+
36+
## 3. Detecting whether a type supports division
37+
38+
We first ask:
39+
40+
> “Can I write `a / b` for this type?”
41+
42+
### Step 3.1 – Primary template (assume NO division)
43+
44+
```cpp
45+
template <typename T, typename = void>
46+
struct has_division : std::false_type {};
47+
```
48+
49+
This says:
50+
51+
* By default, `T` **does not** support division
52+
53+
---
54+
55+
### Step 3.2 – Specialization (only exists if `T / T` is valid)
56+
57+
```cpp
58+
template <typename T>
59+
struct has_division<
60+
T,
61+
std::void_t<decltype(std::declval<T>() / std::declval<T>())>
62+
> : std::true_type {};
63+
```
64+
65+
What happens here:
66+
67+
* `std::declval<T>()` creates a **fake T** (no object needed)
68+
* `decltype(a / b)` checks if the expression is valid
69+
* `std::void_t<...>` turns a valid expression into `void`
70+
71+
If `T / T` is:
72+
73+
* ✅ valid → this specialization exists → `true_type`
74+
* ❌ invalid → substitution fails → specialization ignored
775
8-
Here's a simple example to illustrate SFINAE:
76+
**This is SFINAE in action.**
77+
78+
---
79+
80+
## 4. Enabling the function only when division exists
81+
82+
### Step 4.1 – Function enabled for divisible types
83+
84+
```cpp
85+
template <typename T, std::enable_if_t<has_division<T>::value, int> = 0>
86+
T divide(const T& a, const T& b) {
87+
return a / b;
88+
}
89+
```
90+
91+
Key idea:
92+
93+
* `enable_if_t<condition, int>` exists **only if condition is true**
94+
* If `has_division<T>::value == false`
95+
→ the function is **removed from overload resolution**
96+
97+
---
98+
99+
### Step 4.2 – Fallback for non-divisible types
100+
101+
```cpp
102+
template <typename T, std::enable_if_t<!has_division<T>::value, int> = 0>
103+
void divide(const T&, const T&) {
104+
std::cout << "No division available for this type\n";
105+
}
106+
```
107+
108+
So now:
109+
110+
| Type | Which overload exists |
111+
| ------------- | --------------------- |
112+
| `int` | division overload |
113+
| `double` | division overload |
114+
| `std::string` | fallback overload |
115+
116+
---
117+
118+
## 5. Full working example
9119
10120
```cpp
11121
#include <iostream>
122+
#include <string>
12123
#include <type_traits>
124+
#include <utility>
125+
126+
// 1) Detect division support
127+
template <typename T, typename = void>
128+
struct has_division : std::false_type {};
13129
14-
// Base template
15130
template <typename T>
16-
typename std::enable_if<std::is_integral<T>::value, bool>::type isIntegral(T) {
17-
return true;
131+
struct has_division<
132+
T,
133+
std::void_t<decltype(std::declval<T>() / std::declval<T>())>
134+
> : std::true_type {};
135+
136+
// 2) Enabled only if T supports division
137+
template <typename T, std::enable_if_t<has_division<T>::value, int> = 0>
138+
T divide(const T& a, const T& b) {
139+
return a / b;
18140
}
19141
20-
// Template specialization for non-integral types
21-
template <typename T>
22-
typename std::enable_if<!std::is_integral<T>::value, bool>::type isIntegral(T) {
23-
return false;
142+
// 3) Enabled only if T does NOT support division
143+
template <typename T, std::enable_if_t<!has_division<T>::value, int> = 0>
144+
void divide(const T&, const T&) {
145+
std::cout << "No division available for this type\n";
24146
}
25147
26148
int main() {
27-
std::cout << std::boolalpha;
28-
std::cout << "isIntegral(10): " << isIntegral(10) << std::endl; // Outputs: true
29-
std::cout << "isIntegral(3.14): " << isIntegral(3.14) << std::endl; // Outputs: false
149+
std::cout << divide(10, 2) << "\n"; // OK
150+
std::cout << divide(10.0, 2.0) << "\n"; // OK
30151
31-
return 0;
152+
std::string s1 = "a", s2 = "b";
153+
divide(s1, s2); // graceful fallback
32154
}
33155
```
34156

35-
In this example, there are two versions of the `isIntegral` function template. The first version is enabled (via `std::enable_if`) only for integral types, while the second version is enabled for non-integral types. When you call `isIntegral` with an integer, the first version is instantiated. If you call it with a non-integer, the second version is instantiated.
157+
---
158+
159+
## 6. Why this matters in real APIs
160+
161+
You’ll see SFINAE used to:
162+
163+
* Enable algorithms only for **numeric types**
164+
* Prevent misuse of generic APIs
165+
* Create **type-safe** libraries (Eigen, STL, ranges, fmt, etc.)
166+
* Provide **better overload selection** instead of runtime checks
167+
168+
---
169+
170+
## 7. Mental model to remember
171+
172+
Think of SFINAE like this:
173+
174+
> “If this template substitution doesn’t make sense,
175+
> pretend this function never existed.”
176+
177+
No error. No warning. Just… gone.
178+
179+
---
180+
181+
## 8. Interview-level takeaway
36182

37-
### Explanation
183+
If asked:
38184

39-
- `std::enable_if`: This is a standard library utility that provides a member typedef `type` if the given boolean constant is true. If the boolean is false, there's no member typedef. This utility is commonly used for controlling template instantiation.
185+
> *“What is SFINAE and why do we need it?”*
40186
41-
- `std::is_integral`: This is a type trait that checks if a type is an integral type (like int, char, etc.).
187+
Answer:
42188

43-
### How SFINAE Comes Into Play
189+
> SFINAE lets template overloads disappear when a type does not satisfy certain compile-time requirements, enabling safe, expressive, and type-checked generic APIs without runtime overhead.
44190
45-
In the example, if `T` is an integral type, the `std::enable_if<std::is_integral<T>::value, bool>::type` becomes `bool`, so the first `isIntegral` function template is valid. If `T` is not an integral type, this substitution fails, but due to SFINAE, this failure is not an error; instead, the first `isIntegral` template is simply discarded, and the compiler looks for other templates (in this case, the second `isIntegral`).
191+
---
46192

47-
SFINAE allows for powerful metaprogramming techniques in C++, enabling the creation of templates that can adapt to different types and conditions at compile time, leading to more efficient and tailored code.

0 commit comments

Comments
 (0)