Skip to content

Commit 21bef33

Browse files
authored
Merge pull request #305 from elbeno/same-template-as
✨ Add `same_template_as`
2 parents 0544692 + 5d082a4 commit 21bef33

8 files changed

Lines changed: 77 additions & 8 deletions

File tree

docs/concepts.adoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,14 @@ private:
107107
}
108108
};
109109
----
110+
111+
=== `same_template_as`
112+
113+
`same_template_as` is true when two types are specializations of the same base
114+
template.
115+
116+
[source,cpp]
117+
----
118+
stdx::same_template_as<std::vector<int>, std::vector<float>>; // true
119+
stdx::same_template_as<std::vector<int>, std::list<int>>; // false
120+
----

docs/type_traits.adoc

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,21 @@ stdx::is_function_object_v<decltype(lam)>; // true
9797
stdx::is_function_object_v<decltype(gen_lam)>; // true
9898
----
9999

100+
=== `is_same_template_v`
101+
102+
`is_same_template_v` is a variable template that detects whether two types
103+
are specializations of the same base template.
104+
105+
[source,cpp]
106+
----
107+
stdx::is_same_template_v<std::vector<int>, std::vector<float>>; // true
108+
stdx::is_same_template_v<std::vector<int>, std::list<int>>; // false
109+
----
110+
100111
=== `is_same_unqualified_v`
101112

102-
`is_same_unqualified_v` is a variable template that detects whether a two types
103-
are the same are removing top-level cv-qualifications and references, if any.
113+
`is_same_unqualified_v` is a variable template that detects whether two types
114+
are the same after removing top-level cv-qualifications and references, if any.
104115

105116
[source,cpp]
106117
----

include/stdx/concepts.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ template <typename T> constexpr auto structural = is_structural_v<T>;
110110

111111
template <typename T> constexpr auto complete = is_complete_v<T>;
112112

113+
template <typename T, typename U>
114+
constexpr auto same_template_as = is_same_template_v<T, U>;
115+
113116
#else
114117

115118
// After C++20, we can define concepts that are lacking in the library
@@ -199,6 +202,9 @@ concept structural = is_structural_v<T>;
199202
template <typename T>
200203
concept complete = is_complete_v<T>;
201204

205+
template <typename T, typename U>
206+
concept same_template_as = is_same_template_v<T, U>;
207+
202208
#endif
203209

204210
} // namespace v1
@@ -242,6 +248,9 @@ concept structural = is_structural_v<T>;
242248
template <typename T>
243249
concept complete = is_complete_v<T>;
244250

251+
template <typename T, typename U>
252+
concept same_template_as = is_same_template_v<T, U>;
253+
245254
template <typename T, typename... Us>
246255
constexpr auto same_any = (... or same_as<T, Us>);
247256

include/stdx/ct_conversions.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#pragma once
22

33
#include <stdx/compiler.hpp>
4-
#include <stdx/type_traits.hpp>
54

6-
#include <cstddef>
75
#include <string_view>
86

97
namespace stdx {
108
inline namespace v1 {
9+
template <typename...> constexpr bool always_false_v = false;
10+
1111
template <typename Tag>
1212
CONSTEVAL static auto type_as_string() -> std::string_view {
1313
#ifdef __clang__
@@ -25,6 +25,13 @@ CONSTEVAL static auto type_as_string() -> std::string_view {
2525
return function_name.substr(lhs, rhs - lhs + 1);
2626
}
2727

28+
template <typename T>
29+
CONSTEVAL static auto template_base() -> std::string_view {
30+
constexpr auto t = stdx::type_as_string<T>();
31+
constexpr auto rhs = t.find('<');
32+
return t.substr(0, rhs);
33+
}
34+
2835
template <auto Value>
2936
CONSTEVAL static auto enum_as_string() -> std::basic_string_view<char> {
3037
#ifdef __clang__

include/stdx/type_traits.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <stdx/compiler.hpp>
4+
#include <stdx/ct_conversions.hpp>
45

56
#include <boost/mp11/algorithm.hpp>
67

@@ -42,8 +43,6 @@ using conditional_t = typename detail::conditional<B>::template choice_t<T, U>;
4243
template <template <typename...> typename P, typename X, typename Y = void>
4344
using type_or_t = conditional_t<P<X>::value, X, Y>;
4445

45-
template <typename...> constexpr bool always_false_v = false;
46-
4746
template <typename T>
4847
constexpr bool is_function_v =
4948
not std::is_reference_v<T> and not std::is_const_v<std::add_const_t<T>>;
@@ -274,5 +273,8 @@ STDX_PRAGMA(diagnostic pop)
274273
template <typename T, typename = void> constexpr auto is_complete_v = false;
275274
template <typename T>
276275
constexpr auto is_complete_v<T, detail::void_v<sizeof(T)>> = true;
276+
277+
template <typename T, typename U>
278+
constexpr auto is_same_template_v = template_base<T>() == template_base<U>();
277279
} // namespace v1
278280
} // namespace stdx

test/concepts.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,23 @@ struct non_structural {
172172
};
173173
} // namespace
174174

175-
TEST_CASE("structural", "[type_traits]") {
175+
TEST_CASE("structural", "[concepts]") {
176176
STATIC_REQUIRE(stdx::structural<int>);
177177
STATIC_REQUIRE(not stdx::structural<non_structural>);
178178
}
179179

180-
TEST_CASE("complete", "[type_traits]") {
180+
TEST_CASE("complete", "[concepts]") {
181181
struct incomplete;
182182
STATIC_REQUIRE(stdx::complete<int>);
183183
STATIC_REQUIRE(not stdx::complete<incomplete>);
184184
}
185+
186+
namespace {
187+
template <typename> struct unary_t {};
188+
template <typename...> struct variadic_t {};
189+
} // namespace
190+
191+
TEST_CASE("same_template_as", "[concepts]") {
192+
STATIC_REQUIRE(stdx::same_template_as<unary_t<int>, unary_t<void>>);
193+
STATIC_REQUIRE(not stdx::same_template_as<unary_t<int>, variadic_t<void>>);
194+
}

test/ct_conversions.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ TEST_CASE("type as string", "[ct_conversion]") {
1414
STATIC_REQUIRE(stdx::type_as_string<incomplete>() == "incomplete"sv);
1515
}
1616

17+
template <typename T> struct type_template;
18+
19+
template <auto T> struct value_template;
20+
21+
TEST_CASE("template base", "[ct_conversion]") {
22+
using namespace std::string_view_literals;
23+
STATIC_REQUIRE(stdx::template_base<type_template<int>>() ==
24+
"type_template"sv);
25+
STATIC_REQUIRE(stdx::template_base<value_template<42>>() ==
26+
"value_template"sv);
27+
STATIC_REQUIRE(stdx::template_base<int>() == "int"sv);
28+
}
29+
1730
namespace {
1831
enum A { X };
1932
enum struct B { Y };

test/type_traits.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,3 +275,9 @@ TEST_CASE("is_complete_v", "[type_traits]") {
275275
STATIC_REQUIRE(stdx::is_complete_v<int>);
276276
STATIC_REQUIRE(not stdx::is_complete_v<incomplete>);
277277
}
278+
279+
TEST_CASE("is_same_template_v", "[type_traits]") {
280+
STATIC_REQUIRE(stdx::is_same_template_v<unary_t<int>, unary_t<void>>);
281+
STATIC_REQUIRE(
282+
not stdx::is_same_template_v<unary_t<int>, variadic_t<void>>);
283+
}

0 commit comments

Comments
 (0)