aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/development
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2023-04-12 22:57:27 +0200
committerJohannes Stoelp <johannes.stoelp@gmail.com>2023-04-12 22:57:27 +0200
commitd6deac54dd372c946942637636846893694ce521 (patch)
tree2bcd7d8180cdc6f219c1ae616c9ef42497970b34 /src/development
parenta6d3ae16736d7746ad6827f10c299ad84aa78a5b (diff)
downloadnotes-d6deac54dd372c946942637636846893694ce521.tar.gz
notes-d6deac54dd372c946942637636846893694ce521.zip
c++: improve void_t explanation
Diffstat (limited to 'src/development')
-rw-r--r--src/development/c++.md12
-rw-r--r--src/development/c++/Makefile2
-rw-r--r--src/development/c++/tmpl-void_t.cc47
3 files changed, 52 insertions, 9 deletions
diff --git a/src/development/c++.md b/src/development/c++.md
index 9dc8fb0..6cdc251 100644
--- a/src/development/c++.md
+++ b/src/development/c++.md
@@ -58,17 +58,13 @@ of the `decltype(std:declval<T>...` expressions is ill-formed, the template
specialization for `is_valid` will be removed from the candidate set due to
[SFINAE][sfinae].
```cpp
-template<typename T, typename = void>
-struct is_valid : std::false_type {};
-
-template<typename T>
-struct is_valid<T, std::void_t<
- decltype(std::declval<T>().some_fun1()),
- decltype(std::declval<T>().some_fun2())
- >> : std::true_type {};
+{{#include c++/tmpl-void_t.cc:3:45}}
```
> `std::declval<T>()` creates an instance of type T in an unevaluated context.
+A more detailed description is available in the SO discussion [How does
+`void_t` work](https://stackoverflow.com/a/27688405).
+
## Template selection with partially / fully specializations.
```cpp
{{#include c++/tmpl-pair.cc:3:}}
diff --git a/src/development/c++/Makefile b/src/development/c++/Makefile
index 1d5172b..ca752d9 100644
--- a/src/development/c++/Makefile
+++ b/src/development/c++/Makefile
@@ -1,4 +1,4 @@
-SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc
+SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc
BIN = $(SRC:.cc=)
all: $(BIN)
diff --git a/src/development/c++/tmpl-void_t.cc b/src/development/c++/tmpl-void_t.cc
new file mode 100644
index 0000000..fd95315
--- /dev/null
+++ b/src/development/c++/tmpl-void_t.cc
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 johannst
+
+#include <type_traits>
+
+// (1) Primary template.
+template<typename T, typename = void>
+struct is_valid : std::false_type {};
+
+// (2) Partial template specialization.
+template<typename T>
+struct is_valid<T, std::void_t<decltype(std::declval<T>().some_fun1()),
+ decltype(std::declval<T>().some_fun2())>> : std::true_type {};
+struct A {
+ void some_fun1() {}
+ void some_fun2() {}
+};
+
+struct B {};
+
+static_assert(is_valid<A>::value, "is true");
+// * Compare template arg list with primary template, we only supplied one
+// arg, the second one will be defaulted as
+// is_valid<A, void>
+// * Compare template arg list against available specializations, this will
+// try to match the pattern <A, void> against the patterns defined in the
+// partial specializations.
+// * Try specialization (2)
+// * T -> A
+// * Evaluate std::void_t -> decltype's are well-formed
+// std::void_t<...> -> void
+// * Specialization (2) matches <A, void>
+// * Pick the most specialized version -> (2)
+
+static_assert(!is_valid<B>::value, "is false");
+// * Compare template arg list with primary template, we only supplied one
+// arg, the second one will be defaulted as
+// is_valid<A, void>
+// * Compare template arg list against available specializations, this will
+// try to match the pattern <B, void> against the patterns defined in the
+// partial specializations.
+// * Try specialization (2)
+// * T -> B
+// * Evaluate std::void_t -> decltype's are ill-formed
+// * Specialization (2) is removed from candidate set, no hard error (SFINAE)
+// * No specialization matches, take the primary template.
+
+int main() {}