aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/overloaded.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/overloaded.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/overloaded.h')
-rw-r--r--util/generic/overloaded.h56
1 files changed, 56 insertions, 0 deletions
diff --git a/util/generic/overloaded.h b/util/generic/overloaded.h
new file mode 100644
index 0000000000..96a97e44bc
--- /dev/null
+++ b/util/generic/overloaded.h
@@ -0,0 +1,56 @@
+#pragma once
+
+/**
+ * Construct an ad-hoc object with an overloaded `operator()`.
+ *
+ * Typically used with lambdas to construct type-matching visitors for e.g. std::variant:
+ * ```
+ * std::variant<int, void*, TString> var;
+ * Visit(TOverloaded{
+ * [](int val) { Cerr << "int: " << val; },
+ * [](void* val) { Cerr << "ptr: " << val; },
+ * [](const TString& val) { Cerr << "str: " << val; },
+ * }, var);
+ * ```
+ *
+ * *** IMPORTANT NOTE (IMPLICIT ARGUMENT CONVERSIONS) ***
+ *
+ * Since the resulting objects use regular overloaded method resolution rules,
+ * methods may be called by inexact matches (causing implicit casts), hence this
+ * implementation does not guarantee exhaustiveness of cases.
+ *
+ * For example, the following code will compile and run by casting all values to
+ * double:
+ * ```
+ * std::variant<int, double, char> var;
+ * Visit(TOverloaded{
+ * [](double val) { Cerr << "dbl: " << val; },
+ * }, var);
+ * ```
+ *
+ * If cases may be ambigous or specific type-matching logic is required,
+ * a verbose `if constexpr`-based version would be preferred:
+ * ```
+ * std::variant<int, double, char> var;
+ * Visit([](auto&& val) {
+ * using T = std::decay_t<decltype(val)>;
+ * if constexpr (std::is_same_v<T, int>) {
+ * Cerr << "int: " << val;
+ * } else if constexpr (std::is_same_v<T, double>) {
+ * Cerr << "dbl: " << val;
+ * } else if constexpr (std::is_same_v<T, char>) {
+ * Cerr << "chr: " << val;
+ * } else {
+ * static_assert(TDependentFalse<T>, "unexpected type");
+ * }
+ * }, var);
+ * ```
+ */
+
+template <class... Fs>
+struct TOverloaded: Fs... {
+ using Fs::operator()...;
+};
+
+template <class... Fs>
+TOverloaded(Fs...) -> TOverloaded<Fs...>;