Skip to content

Commit 0698bb6

Browse files
authored
Feature invocable and function (#34)
* fixing the Ascii doc from C to C++ * ✨ added is_function and is_invocable features * ✨ updated the operators for callable list and its example * 💚 fixed the CI build issue
1 parent c201f7f commit 0698bb6

File tree

5 files changed

+613
-435
lines changed

5 files changed

+613
-435
lines changed

docs/utility.adoc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,41 @@ using select_f_c_t {
9494
* `select_qmf_c_t` => to avoid `::type`
9595
* `select_qmf` => when `false` type is captured with quoted meta function, and condition is a type
9696
* `select_qmf_t` => to avoid `::type`
97+
98+
=== is_function
99+
100+
This will check if the provided type is a function or not.
101+
102+
[source, cpp]
103+
template <typename T>
104+
struct is_function {
105+
...
106+
};
107+
108+
If the provided type is not a reference and adding const to type will not result in the const, then it is considered as function.
109+
110+
variants of `is_function` are:
111+
112+
* `is_function_t` => to avoid using `::type`
113+
* `is_function_v` => to avoid using `::value`
114+
115+
=== is_invocable
116+
117+
This will check if the provided type is a `function` OR a class which implements `operator()`
118+
119+
[source, cpp]
120+
template <typename T>
121+
struct is_invocable {
122+
...
123+
};
124+
125+
It makes use of the https://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector[CPP member detection idiom] technique.
126+
127+
If the provided T is a function, then it will result in `std::true_type`
128+
If the provided T is a class, if it implements `operator()` then it will result in `std::true_type`
129+
otherwise it will result in `std::false_type`
130+
131+
variants of `is_invocable` are:
132+
133+
* `is_invocable_t` => to avoid using `::type`
134+
* `is_invocable_v` => to avoid using `::value`

include/container/list.hpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#pragma once
22

3+
#include <utils.hpp>
4+
// #include <type_traits>
5+
36
namespace ctl {
47

58
// list
@@ -11,6 +14,16 @@ struct ilist {};
1114

1215
template <typename... types>
1316
struct clist : public ilist<types...> {
17+
private:
18+
constexpr static auto get_value = []<typename T>() {
19+
if constexpr (ctl::is_invocable_v<T>) {
20+
return T{}();
21+
} else {
22+
return T::value;
23+
}
24+
};
25+
26+
public:
1427
constexpr auto operator()() {
1528
return (types{}(), ...);
1629
}
@@ -19,8 +32,39 @@ struct clist : public ilist<types...> {
1932
return (predicate(types{}), ...);
2033
}
2134

35+
// bitwise
36+
constexpr auto operator|(auto initialVal) {
37+
return (initialVal | ... | (get_value.template operator()<types>()));
38+
}
39+
40+
constexpr auto operator&(auto initialVal) {
41+
return (initialVal & ... & (get_value.template operator()<types>()));
42+
}
43+
44+
constexpr auto operator^(auto initialVal) {
45+
return (initialVal ^ ... ^ (get_value.template operator()<types>()));
46+
}
47+
48+
// logical
2249
constexpr auto operator||(auto inital_val) -> bool {
23-
return (types{} || ... || inital_val);
50+
return (inital_val || ... || (get_value.template operator()<types>()));
51+
}
52+
53+
constexpr auto operator&&(auto inital_val) -> bool {
54+
return (inital_val && ... && (get_value.template operator()<types>()));
55+
}
56+
57+
// Calculative
58+
constexpr auto operator+(auto initialVal) {
59+
return (initialVal + ... + (get_value.template operator()<types>()));
60+
}
61+
62+
constexpr auto operator-(auto initialVal) {
63+
return (initialVal - ... - (get_value.template operator()<types>()));
64+
}
65+
66+
constexpr auto operator*(auto initialVal) {
67+
return (initialVal * ... * (get_value.template operator()<types>()));
2468
}
2569

2670
// TODO: other operators!!

include/utils.hpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,59 @@ using select_qmf = select_f<C, T, QMF::template fn, Ts...>;
126126
template <typename C, typename T, typename QMF, typename... Ts>
127127
using select_qmf_t = typename select_qmf<C, T, QMF, Ts...>::type;
128128

129+
// is_function
130+
template <typename T>
131+
struct is_function {
132+
private:
133+
struct is_function_impl {
134+
constexpr static bool value = !std::is_reference_v<T> && !std::is_const_v<std::add_const_t<T>>;
135+
};
136+
137+
public:
138+
using type = std::integral_constant<bool, is_function_impl::value>;
139+
};
140+
141+
template <typename T>
142+
using is_function_t = typename is_function<T>::type;
143+
144+
template <typename T>
145+
constexpr static auto is_function_v = is_function_t<T>::value;
146+
147+
// is invocable
148+
/*
149+
using member detection idiom:
150+
https://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector
151+
*/
152+
template <typename T>
153+
struct is_invocable {
154+
private:
155+
// member detection idiom. member to detect here is 'operator()'
156+
struct call_operator {
157+
auto operator()() -> void {};
158+
};
159+
160+
template <typename F, bool>
161+
struct derived : call_operator {};
162+
163+
template <typename F>
164+
struct derived <F, true> : F, call_operator {};
165+
166+
//invocable impl
167+
//if T also has operator() defined, then there will be ambiguity in the std::void_t<> will be ill-formed, so only true_type is accepted.
168+
template <typename, typename = void>
169+
struct is_invocable_impl : public std::true_type {};
170+
171+
template <typename U>
172+
struct is_invocable_impl<U, std::void_t< decltype(& derived<U, std::is_class_v<U>>::operator()) > > : public std::false_type {};
173+
174+
public:
175+
using type = std::integral_constant<bool, is_function_v<T> || is_invocable_impl<T>::value>;
176+
};
177+
178+
template <typename T>
179+
using is_invocable_t = typename is_invocable<T>::type;
180+
181+
template <typename T>
182+
constexpr static auto is_invocable_v = is_invocable_t<T>::value;
183+
129184
} // namespace ctl

src/main.cpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,25 @@ struct super_type {
77
auto attendence() const {
88
std::cout << "Present" << std::endl;
99
}
10+
11+
virtual void name() const = 0;
1012
};
11-
1213
struct type1 : public super_type {
13-
auto operator()() {
14-
std::cout << "inside type1\n";
14+
void name() const {
15+
std::cout << "type1: ";
1516
}
1617

17-
auto operator||(auto val) {
18-
return val || false;
18+
auto operator()() const -> bool {
19+
return false;
1920
}
2021
};
21-
2222
struct type2 : public super_type {
23-
auto operator()() {
24-
std::cout << "inside type2\n";
23+
void name() const {
24+
std::cout << "type2: ";
2525
}
2626

27-
auto operator||(auto val) {
28-
return val || false;
27+
auto operator()() const -> bool {
28+
return true;
2929
}
3030
};
3131

@@ -50,16 +50,23 @@ int main() {
5050

5151
// with predicate!
5252
constexpr auto fn = [](auto const& obj) {
53+
obj.name();
5354
obj.attendence();
5455
};
56+
5557
ctypes_all{}(fn);
5658

57-
// with operator logical OR
58-
if (ctypes_all{} || false) {
59-
std::cout << "Operation Logical OR returned true" << std::endl;
60-
} else {
61-
std::cout << "Operation Logical OR returned false" << std::endl;
62-
}
59+
// Operator overloading
60+
using numList = ctl::clist<std::integral_constant<uint32_t, 1>,std::integral_constant<uint32_t, 2>, std::integral_constant<uint32_t, 3>>;
61+
std::cout << "operator|: " << (numList{} | 0) << std::endl;
62+
std::cout << "operator&: " << (numList{} & 0xFF) << std::endl;
63+
std::cout << "operator^: " << (numList{} ^ 0) << std::endl;
64+
std::cout << "operator^: " << (numList{} ^ 0xFF) << std::endl;
65+
std::cout << "operator||: " << (ctypes_all{} || false) << std::endl;
66+
std::cout << "operator&&: " << (ctypes_all{} && true) << std::endl;
67+
std::cout << "operator+: " << (numList{} + 10) << std::endl;
68+
std::cout << "operator-: " << (numList{} - 10) << std::endl;
69+
std::cout << "operator*: " << (numList{} * 10) << std::endl;
6370
}
6471

6572
return 0;

0 commit comments

Comments
 (0)