diff --git a/.github/workflows/bvt-clang.yml b/.github/workflows/bvt-clang.yml index fd4bbfa8..984d40ce 100644 --- a/.github/workflows/bvt-clang.yml +++ b/.github/workflows/bvt-clang.yml @@ -15,21 +15,14 @@ jobs: - name: install clang run: | - sudo apt install -y clang-15 clang-16 clang-17 clang-18 + sudo apt install -y clang-16 clang-17 clang-18 - name: check compiler versions run: | - clang++-15 --version clang++-16 --version clang++-17 --version clang++-18 --version - - name: build and run test with clang 15 - run: | - cmake -B build-clang-15 -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang++-15 -DCMAKE_BUILD_TYPE=Release - cmake --build build-clang-15 -j - ctest --test-dir build-clang-15 -j - - name: build and run test with clang 16 run: | cmake -B build-clang-16 -DCMAKE_C_COMPILER=clang-16 -DCMAKE_CXX_COMPILER=clang++-16 -DCMAKE_BUILD_TYPE=Release diff --git a/README.md b/README.md index 2b924d3d..ef9ef572 100644 --- a/README.md +++ b/README.md @@ -167,7 +167,7 @@ The "Proxy" library is a self-contained solution for runtime polymorphism in C++ | Family | Minimum version | Required flags | | ---------- | --------------- | -------------- | | GCC | 13.1 | -std=c++20 | -| Clang | 15.0.0 | -std=c++20 | +| Clang | 16.0.0 | -std=c++20 | | MSVC | 19.31 | /std:c++20 | | NVIDIA HPC | 24.1 | -std=c++20 | diff --git a/proxy.h b/proxy.h index 437dfe95..6378f8e7 100644 --- a/proxy.h +++ b/proxy.h @@ -520,6 +520,12 @@ template using merged_composite_accessor = typename composite_accessor_merge_traits::type; +template struct in_place_type_traits : inapplicable_traits {}; +template +struct in_place_type_traits> : applicable_traits {}; +template +constexpr bool is_in_place_type = in_place_type_traits::applicable; + template consteval bool is_facade_constraints_well_formed() { if constexpr (requires { @@ -782,14 +788,15 @@ class proxy : public details::facade_traits::direct_accessor { } template proxy(P&& ptr) noexcept(std::is_nothrow_constructible_v, P>) - requires(proxiable, F> && - std::is_constructible_v, P>) : proxy() - { initialize>(std::forward

(ptr)); } + requires(!details::is_in_place_type> && + proxiable, F> && + std::is_constructible_v, P>) + : proxy() { initialize>(std::forward

(ptr)); } template P, class... Args> explicit proxy(std::in_place_type_t

, Args&&... args) noexcept(std::is_nothrow_constructible_v) - requires(std::is_constructible_v) : proxy() - { initialize

(std::forward(args)...); } + requires(std::is_constructible_v) + : proxy() { initialize

(std::forward(args)...); } template P, class U, class... Args> explicit proxy(std::in_place_type_t

, std::initializer_list il, Args&&... args) @@ -1258,8 +1265,6 @@ template using adl_accessor_arg_t = std::conditional_t, proxy_indirect_accessor>; -template -using overload_return_type = typename overload_traits::return_type; #define ___PRO_DEF_CAST_ACCESSOR(Q, SELF, ...) \ template \ struct accessor<__F, __C, T() Q> { \ @@ -1274,7 +1279,7 @@ using overload_return_type = typename overload_traits::return_type; template struct cast_dispatch_base { ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_CAST_ACCESSOR, - operator overload_return_type<__Os>) + operator typename overload_traits<__Os>::return_type) }; #undef ___PRO_DEF_CAST_ACCESSOR @@ -1468,11 +1473,10 @@ struct observer_overload_mapping_traits : observer_overload_mapping_traits_impl {}; template struct observer_overload_mapping_traits - : std::type_identity, - const facade_of_t::return_type>, - facade_of_t::return_type> - >>() const noexcept> {}; + : std::type_identity, + const facade_of_t::return_type>, + facade_of_t::return_type>>>() + const noexcept> {}; template struct observer_dispatch_reduction : std::type_identity {}; @@ -1702,22 +1706,20 @@ struct basic_facade_builder { using support_destruction = basic_facade_builder< Cs, Rs, details::make_destructible(C, CL)>; #ifdef __cpp_rtti - using support_indirect_rtti = - basic_facade_builder< - details::add_conv_t>, - details::add_tuple_t>, C>; - using support_direct_rtti = - basic_facade_builder< - details::add_conv_t>, - details::add_tuple_t>, C>; + using support_indirect_rtti = basic_facade_builder< + details::add_conv_t>, + details::add_tuple_t>, C>; + using support_direct_rtti = basic_facade_builder< + details::add_conv_t>, + details::add_tuple_t>, C>; using support_rtti = support_indirect_rtti; #endif // __cpp_rtti template @@ -1783,8 +1785,8 @@ struct operator_dispatch; #define ___PRO_LHS_BINARY_OP_DISPATCH_BODY_IMPL(...) \ template \ decltype(auto) operator()(T&& self, Arg&& arg) \ - ___PRO_DIRECT_FUNC_IMPL(std::forward(self) __VA_ARGS__ \ - std::forward(arg)) + ___PRO_DIRECT_FUNC_IMPL( \ + std::forward(self) __VA_ARGS__ std::forward(arg)) #define ___PRO_LHS_ALL_OP_DISPATCH_BODY_IMPL(...) \ ___PRO_LHS_LEFT_OP_DISPATCH_BODY_IMPL(__VA_ARGS__) \ ___PRO_LHS_BINARY_OP_DISPATCH_BODY_IMPL(__VA_ARGS__) @@ -1792,8 +1794,8 @@ struct operator_dispatch; template <> \ struct operator_dispatch<#__VA_ARGS__, false> { \ ___PRO_LHS_##TYPE##_OP_DISPATCH_BODY_IMPL(__VA_ARGS__) \ - ___PRO_DEF_MEM_ACCESSOR_TEMPLATE(___PRO_DEF_LHS_##TYPE##_OP_ACCESSOR, \ - operator __VA_ARGS__) \ + ___PRO_DEF_MEM_ACCESSOR_TEMPLATE( \ + ___PRO_DEF_LHS_##TYPE##_OP_ACCESSOR, operator __VA_ARGS__) \ }; #define ___PRO_DEF_RHS_OP_ACCESSOR(Q, NE, SELF_ARG, SELF, ...) \ @@ -1817,10 +1819,10 @@ ___PRO_DEBUG( \ struct operator_dispatch<#__VA_ARGS__, true> { \ template \ decltype(auto) operator()(T&& self, Arg&& arg) \ - ___PRO_DIRECT_FUNC_IMPL(std::forward(arg) __VA_ARGS__ \ - std::forward(self)) \ - ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_RHS_OP_ACCESSOR, \ - __VA_ARGS__) \ + ___PRO_DIRECT_FUNC_IMPL( \ + std::forward(arg) __VA_ARGS__ std::forward(self)) \ + ___PRO_DEF_FREE_ACCESSOR_TEMPLATE( \ + ___PRO_DEF_RHS_OP_ACCESSOR, __VA_ARGS__) \ }; #define ___PRO_EXTENDED_BINARY_OP_DISPATCH_IMPL(...) \ @@ -1873,8 +1875,8 @@ ___PRO_DEBUG( \ struct operator_dispatch<#__VA_ARGS__, true> { \ template \ decltype(auto) operator()(T&& self, Arg&& arg) \ - ___PRO_DIRECT_FUNC_IMPL(std::forward(arg) __VA_ARGS__ \ - std::forward(self)) \ + ___PRO_DIRECT_FUNC_IMPL( \ + std::forward(arg) __VA_ARGS__ std::forward(self)) \ ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_RHS_ASSIGNMENT_OP_ACCESSOR, \ __VA_ARGS__) \ }; @@ -1960,8 +1962,7 @@ struct implicit_conversion_dispatch template T&& operator()(T&& self) noexcept { return std::forward(self); } }; -struct explicit_conversion_dispatch - : details::cast_dispatch_base { +struct explicit_conversion_dispatch : details::cast_dispatch_base { template auto operator()(T&& self) noexcept { return details::explicit_conversion_adapter{std::forward(self)}; } diff --git a/tests/proxy_creation_tests.cpp b/tests/proxy_creation_tests.cpp index f5be550a..16e5a80a 100644 --- a/tests/proxy_creation_tests.cpp +++ b/tests/proxy_creation_tests.cpp @@ -80,6 +80,16 @@ static_assert(!pro::inplace_proxiable_target(std::declval()))); static_assert(noexcept(pro::make_proxy_inplace(123))); +template +void SfinaeUnsafeIncrementImpl(T&& value) { ++value; } + +PRO_DEF_FREE_DISPATCH(FreeSfinaeUnsafeIncrement, SfinaeUnsafeIncrementImpl, Increment); + +struct SfinaeUnsafeFacade : pro::facade_builder + ::support_rtti + ::add_convention + ::build {}; + } // namespace proxy_creation_tests_details namespace details = proxy_creation_tests_details; @@ -535,3 +545,9 @@ TEST(ProxyCreationTests, TestMakeProxy_WithoutSBO_Lifetime_Move) { expected_ops.emplace_back(1, utils::LifetimeOperationType::kDestruction); ASSERT_TRUE(tracker.GetOperations() == expected_ops); } + +TEST(ProxyCreationTests, TestMakeProxy_SfinaeUnsafe) { + pro::proxy p = pro::make_proxy(); + Increment(*p); + ASSERT_EQ(proxy_cast(*p), 1); +}