Просмотр исходного кода

[util] Store policy should preserve constructor's is_constructible trait

Without constraints on the types of arguments, it is possible that creating an instance of `Policy<T>{}` leads to a compilation error, although immediately before that, checking `std::is_default_constructible_v<TPolicy<T>>` returned `true` value
swarmer 1 год назад
Родитель
Сommit
adb1ae56bc
2 измененных файлов с 34 добавлено и 7 удалено
  1. 3 7
      util/generic/store_policy.h
  2. 31 0
      util/generic/store_policy_ut.cpp

+ 3 - 7
util/generic/store_policy.h

@@ -5,11 +5,7 @@
 
 template <class TBase, class TCounter>
 struct TWithRefCount: public TBase, public TRefCounted<TWithRefCount<TBase, TCounter>, TCounter> {
-    template <typename... Args>
-    inline TWithRefCount(Args&&... args)
-        : TBase(std::forward<Args>(args)...)
-    {
-    }
+    using TBase::TBase;
 };
 
 template <class T>
@@ -32,7 +28,7 @@ struct TPtrPolicy {
 
 template <class T>
 struct TEmbedPolicy {
-    template <typename... Args>
+    template <typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
     inline TEmbedPolicy(Args&&... args)
         : T_(std::forward<Args>(args)...)
     {
@@ -53,7 +49,7 @@ template <class T, class TCounter>
 struct TRefPolicy {
     using THelper = TWithRefCount<T, TCounter>;
 
-    template <typename... Args>
+    template <typename... Args, typename = typename std::enable_if<std::is_constructible<T, Args...>::value>::type>
     inline TRefPolicy(Args&&... args)
         : T_(new THelper(std::forward<Args>(args)...))
     {

+ 31 - 0
util/generic/store_policy_ut.cpp

@@ -83,4 +83,35 @@ Y_UNIT_TEST_SUITE(StorePolicy) {
             UNIT_ASSERT_VALUES_EQUAL(**secondHolder.Ptr(), 42);
         });
     }
+
+    struct TNoDefaultConstructible {
+        explicit TNoDefaultConstructible(int) noexcept {
+        }
+    };
+
+    template <class TType, class TBaseType>
+    static void TestStoryPolicyConstructors() {
+        if constexpr (std::is_default_constructible_v<TType>) {
+            TType instance{};
+            Y_UNUSED(instance);
+        }
+        UNIT_ASSERT_VALUES_EQUAL(std::is_default_constructible_v<TType>, std::is_default_constructible_v<TBaseType>);
+        if constexpr (std::is_constructible_v<TType, int>) {
+            TType instance{4};
+            Y_UNUSED(instance);
+        }
+        UNIT_ASSERT_VALUES_EQUAL((std::is_constructible_v<TType, int>), (std::is_constructible_v<TBaseType, int>));
+    }
+
+    template <class TBaseType>
+    static void TestWrapperConstructors() {
+        TestStoryPolicyConstructors<TWithRefCount<TBaseType, TAtomicCounter>, TBaseType>();
+        TestStoryPolicyConstructors<TEmbedPolicy<TBaseType>, TBaseType>();
+        TestStoryPolicyConstructors<TSimpleRefPolicy<TBaseType>, TBaseType>();
+    }
+
+    Y_UNIT_TEST(ConstructorTraits) {
+        TestWrapperConstructors<TNoDefaultConstructible>();
+        TestWrapperConstructors<TVector<short>>();
+    }
 }