Skip to content

Commit f41324b

Browse files
committed
🐛 Fix ambiguity with ct
Problem: - `ct` must use a function template to obtain overloads for both type template parameters and NTTPs. However when using `ct` with an NTTP placeholder type there is an ambiguity if the NTTP is not deduced: e.g. if a non-deduced `ct_string` is passed, both the `auto` overload and the `ct_string` overloads match. Solution: - Introduce another NTTP placeholder type, `ct_helper` that can be partially specialized (without definition) to disable the primary template specialization.
1 parent a3886fa commit f41324b

File tree

4 files changed

+28
-4
lines changed

4 files changed

+28
-4
lines changed

include/stdx/ct_string.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#if __cplusplus >= 202002L
44

55
#include <stdx/compiler.hpp>
6+
#include <stdx/utility.hpp>
67

78
#include <array>
89
#include <cstddef>
@@ -128,6 +129,10 @@ constexpr auto operator+(cts_t<X>, cts_t<Y>) {
128129
return cts_t<X + Y>{};
129130
}
130131

132+
namespace detail {
133+
template <std::size_t N> struct ct_helper<ct_string<N>>;
134+
} // namespace detail
135+
131136
template <ct_string Value> CONSTEVAL auto ct() { return cts_t<Value>{}; }
132137

133138
inline namespace literals {

include/stdx/utility.hpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,23 @@ constexpr auto is_aligned_with = [](auto v) -> bool {
193193
}
194194
};
195195

196-
template <auto Value> CONSTEVAL auto ct() {
197-
return std::integral_constant<decltype(Value), Value>{};
196+
#if __cplusplus >= 202002L
197+
198+
namespace detail {
199+
template <typename T> struct ct_helper {
200+
// NOLINTNEXTLINE(google-explicit-constructor)
201+
CONSTEVAL ct_helper(T t) : value(t) {}
202+
T value;
203+
};
204+
template <typename T> ct_helper(T) -> ct_helper<T>;
205+
} // namespace detail
206+
207+
template <detail::ct_helper Value> CONSTEVAL auto ct() {
208+
return std::integral_constant<decltype(Value.value), Value.value>{};
198209
}
199210
template <typename T> CONSTEVAL auto ct() { return type_identity<T>{}; }
211+
212+
#endif
200213
} // namespace v1
201214
} // namespace stdx
202215

test/ct_string.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ TEST_CASE("wrap ct_string in type", "[ct_string]") {
139139

140140
TEST_CASE("ct (ct_string)", "[ct_string]") {
141141
using namespace stdx::ct_string_literals;
142-
constexpr auto v = stdx::ct<"Hello">();
143-
static_assert(v == "Hello"_ctst);
142+
constexpr auto v1 = stdx::ct<"Hello">();
143+
static_assert(v1 == "Hello"_ctst);
144+
constexpr auto v2 = stdx::ct<"Hello"_cts>();
145+
static_assert(v2 == "Hello"_ctst);
144146
}

test/utility.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ TEST_CASE("is_aligned_with (pointer)", "[utility]") {
204204
CHECK(stdx::is_aligned_with<std::uint32_t>(p));
205205
}
206206

207+
#if __cplusplus >= 202002L
208+
207209
TEST_CASE("ct (integral)", "[utility]") {
208210
constexpr auto vs = stdx::ct<42>();
209211
static_assert(
@@ -239,3 +241,5 @@ TEST_CASE("ct (type)", "[utility]") {
239241
constexpr auto v = stdx::ct<int>();
240242
static_assert(std::is_same_v<decltype(v), stdx::type_identity<int> const>);
241243
}
244+
245+
#endif

0 commit comments

Comments
 (0)