Skip to content

Commit 5d56ef7

Browse files
committed
refactor(uninitialized): Improve construct() overload resolution
IMPROVEMENTS: 1. Add explicit zero-argument overload to avoid SFINAE ambiguity 2. Require at least one argument (A1) for parameterized overloads 3. Better separation between direct initialization and aggregate initialization BENEFITS: - Clearer intent: zero-argument construction is explicitly handled - Avoids potential SFINAE ambiguity when empty parameter pack is used - More maintainable: easier to understand which overload is selected - Consistent with modern C++ best practices for variadic templates TECHNICAL DETAILS: - Zero-arg overload: Always uses T() for value initialization - One-or-more-arg overload: Uses SFINAE to choose between: * T(args...) for types with matching constructor * T{args...} for aggregate types or types with initializer_list ctor This is a code quality improvement and does not fix any compilation issues, but provides better template overload resolution.
1 parent eede001 commit 5d56ef7

File tree

1 file changed

+21
-9
lines changed

1 file changed

+21
-9
lines changed

include/libipc/imp/uninitialized.h

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,32 @@ namespace ipc {
2121
* \see https://en.cppreference.com/w/cpp/memory/construct_at
2222
*/
2323

24-
template <typename T, typename... A>
25-
auto construct(void *p, A &&...args)
26-
-> std::enable_if_t<::std::is_constructible<T, A...>::value, T *> {
24+
// Overload for zero arguments - use value initialization
25+
template <typename T>
26+
T* construct(void *p) {
27+
#if defined(LIBIPC_CPP_20)
28+
return std::construct_at(static_cast<T *>(p));
29+
#else
30+
return ::new (p) T();
31+
#endif
32+
}
33+
34+
// Overload for one or more arguments - prefer direct initialization
35+
template <typename T, typename A1, typename... A>
36+
auto construct(void *p, A1 &&arg1, A &&...args)
37+
-> std::enable_if_t<::std::is_constructible<T, A1, A...>::value, T *> {
2738
#if defined(LIBIPC_CPP_20)
28-
return std::construct_at(static_cast<T *>(p), std::forward<A>(args)...);
39+
return std::construct_at(static_cast<T *>(p), std::forward<A1>(arg1), std::forward<A>(args)...);
2940
#else
30-
return ::new (p) T(std::forward<A>(args)...);
41+
return ::new (p) T(std::forward<A1>(arg1), std::forward<A>(args)...);
3142
#endif
3243
}
3344

34-
template <typename T, typename... A>
35-
auto construct(void *p, A &&...args)
36-
-> std::enable_if_t<!::std::is_constructible<T, A...>::value, T *> {
37-
return ::new (p) T{std::forward<A>(args)...};
45+
// Overload for non-constructible types - use aggregate initialization
46+
template <typename T, typename A1, typename... A>
47+
auto construct(void *p, A1 &&arg1, A &&...args)
48+
-> std::enable_if_t<!::std::is_constructible<T, A1, A...>::value, T *> {
49+
return ::new (p) T{std::forward<A1>(arg1), std::forward<A>(args)...};
3850
}
3951

4052
/**

0 commit comments

Comments
 (0)