[libcxx-commits] [libcxx] [libc++] Add the __is_replaceable type trait (PR #132408)

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Fri Mar 21 12:16:22 PDT 2025


================
@@ -0,0 +1,269 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <__type_traits/is_replaceable.h>
+#include <array>
+#include <deque>
+#include <exception>
+#include <expected>
+#include <memory>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <variant>
+#include <vector>
+
+#include "constexpr_char_traits.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+#  include <locale>
+#endif
+
+template <class T>
+struct NonPropagatingStatefulMoveAssignAlloc : std::allocator<T> {
+  using propagate_on_container_move_assignment = std::false_type;
+  using is_always_equal                        = std::false_type;
+};
+
+template <class T>
+struct NonPropagatingStatefulCopyAssignAlloc : std::allocator<T> {
+  using propagate_on_container_copy_assignment = std::false_type;
+  using is_always_equal                        = std::false_type;
+};
+
+template <class T>
+struct NonPropagatingStatelessMoveAssignAlloc : std::allocator<T> {
+  using propagate_on_container_move_assignment = std::false_type;
+  using is_always_equal                        = std::true_type;
+};
+
+template <class T>
+struct NonPropagatingStatelessCopyAssignAlloc : std::allocator<T> {
+  using propagate_on_container_copy_assignment = std::false_type;
+  using is_always_equal                        = std::true_type;
+};
+
+struct Empty {};
+static_assert(std::__is_replaceable<char>::value, "");
+static_assert(std::__is_replaceable<int>::value, "");
+static_assert(std::__is_replaceable<double>::value, "");
+static_assert(std::__is_replaceable<Empty>::value, "");
+
+struct TriviallyCopyable {
+  char c;
+  int i;
+  Empty s;
+};
+static_assert(std::__is_replaceable<TriviallyCopyable>::value, "");
+
+struct NotTriviallyCopyable {
+  NotTriviallyCopyable(const NotTriviallyCopyable&);
+  ~NotTriviallyCopyable();
+};
+static_assert(!std::__is_replaceable<NotTriviallyCopyable>::value, "");
+
+struct MoveOnlyTriviallyCopyable {
+  MoveOnlyTriviallyCopyable(const MoveOnlyTriviallyCopyable&)            = delete;
+  MoveOnlyTriviallyCopyable& operator=(const MoveOnlyTriviallyCopyable&) = delete;
+  MoveOnlyTriviallyCopyable(MoveOnlyTriviallyCopyable&&)                 = default;
+  MoveOnlyTriviallyCopyable& operator=(MoveOnlyTriviallyCopyable&&)      = default;
+};
+static_assert(std::__is_replaceable<MoveOnlyTriviallyCopyable>::value, "");
+
+struct CustomCopyAssignment {
+  CustomCopyAssignment(const CustomCopyAssignment&) = default;
+  CustomCopyAssignment(CustomCopyAssignment&&)      = default;
+  CustomCopyAssignment& operator=(const CustomCopyAssignment&);
+  CustomCopyAssignment& operator=(CustomCopyAssignment&&) = default;
+};
+static_assert(!std::__is_replaceable<CustomCopyAssignment>::value, "");
+
+struct CustomMoveAssignment {
+  CustomMoveAssignment(const CustomMoveAssignment&)            = default;
+  CustomMoveAssignment(CustomMoveAssignment&&)                 = default;
+  CustomMoveAssignment& operator=(const CustomMoveAssignment&) = default;
+  CustomMoveAssignment& operator=(CustomMoveAssignment&&);
+};
+static_assert(!std::__is_replaceable<CustomMoveAssignment>::value, "");
+
+// library-internal types
+// ----------------------
+
+// __split_buffer
+static_assert(std::__is_replaceable<std::__split_buffer<int> >::value, "");
+static_assert(std::__is_replaceable<std::__split_buffer<NotTriviallyCopyable> >::value, "");
+static_assert(!std::__is_replaceable<std::__split_buffer<int, NonPropagatingStatefulCopyAssignAlloc<int> > >::value,
+              "");
+static_assert(!std::__is_replaceable<std::__split_buffer<int, NonPropagatingStatefulMoveAssignAlloc<int> > >::value,
+              "");
+static_assert(std::__is_replaceable<std::__split_buffer<int, NonPropagatingStatelessCopyAssignAlloc<int> > >::value,
+              "");
+static_assert(std::__is_replaceable<std::__split_buffer<int, NonPropagatingStatelessMoveAssignAlloc<int> > >::value,
+              "");
+
+// standard library types
+// ----------------------
+
+// array
+static_assert(std::__is_replaceable<std::array<int, 0> >::value, "");
+static_assert(std::__is_replaceable<std::array<NotTriviallyCopyable, 0> >::value, "");
+static_assert(std::__is_replaceable<std::array<std::unique_ptr<int>, 0> >::value, "");
+
+static_assert(std::__is_replaceable<std::array<int, 1> >::value, "");
+static_assert(!std::__is_replaceable<std::array<NotTriviallyCopyable, 1> >::value, "");
+static_assert(std::__is_replaceable<std::array<std::unique_ptr<int>, 1> >::value, "");
+
+// basic_string
+struct MyChar {
+  char c;
+};
+template <class T>
+struct NotReplaceableCharTraits : constexpr_char_traits<T> {
+  NotReplaceableCharTraits(const NotReplaceableCharTraits&);
+  NotReplaceableCharTraits& operator=(const NotReplaceableCharTraits&);
+  ~NotReplaceableCharTraits();
+};
+
+static_assert(std::__is_replaceable<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::value,
+              "");
+static_assert(
+    std::__is_replaceable<std::basic_string<char, NotReplaceableCharTraits<char>, std::allocator<char> > >::value, "");
+static_assert(
+    std::__is_replaceable<std::basic_string<MyChar, constexpr_char_traits<MyChar>, std::allocator<MyChar> > >::value,
+    "");
+static_assert(!std::__is_replaceable<std::basic_string<char, std::char_traits<char>, test_allocator<char> > >::value,
+              "");
----------------
mordante wrote:

I wonder whether we should assert `test_allocator` is not replacable, or make it explicitly not replacable in the `test_allocator.h` header. It now feels like we depend on an accidental property of the class.

https://github.com/llvm/llvm-project/pull/132408


More information about the libcxx-commits mailing list