Quellcode durchsuchen

entt: more concepts, less sfinae

skypjack vor 1 Monat
Ursprung
Commit
e74aac0626

+ 1 - 2
src/entt/core/algorithm.hpp

@@ -76,9 +76,8 @@ struct insertion_sort {
  * @tparam N Maximum number of bits to sort.
  * @tparam N Maximum number of bits to sort.
  */
  */
 template<std::size_t Bit, std::size_t N>
 template<std::size_t Bit, std::size_t N>
+requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass
 struct radix_sort {
 struct radix_sort {
-    static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
-
     /**
     /**
      * @brief Sorts the elements in a range.
      * @brief Sorts the elements in a range.
      *
      *

+ 4 - 5
src/entt/core/compressed_pair.hpp

@@ -205,22 +205,22 @@ public:
      * reference to the second element if `Index` is 1.
      * reference to the second element if `Index` is 1.
      */
      */
     template<std::size_t Index>
     template<std::size_t Index>
+    requires (Index <= 1u)
     [[nodiscard]] constexpr decltype(auto) get() noexcept {
     [[nodiscard]] constexpr decltype(auto) get() noexcept {
         if constexpr(Index == 0u) {
         if constexpr(Index == 0u) {
             return first();
             return first();
         } else {
         } else {
-            static_assert(Index == 1u, "Index out of bounds");
             return second();
             return second();
         }
         }
     }
     }
 
 
     /*! @copydoc get */
     /*! @copydoc get */
     template<std::size_t Index>
     template<std::size_t Index>
+    requires (Index <= 1u)
     [[nodiscard]] constexpr decltype(auto) get() const noexcept {
     [[nodiscard]] constexpr decltype(auto) get() const noexcept {
         if constexpr(Index == 0u) {
         if constexpr(Index == 0u) {
             return first();
             return first();
         } else {
         } else {
-            static_assert(Index == 1u, "Index out of bounds");
             return second();
             return second();
         }
         }
     }
     }
@@ -265,9 +265,8 @@ struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_
  * @tparam Second The type of the second element that the pair stores.
  * @tparam Second The type of the second element that the pair stores.
  */
  */
 template<size_t Index, typename First, typename Second>
 template<size_t Index, typename First, typename Second>
-struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
-    static_assert(Index < 2u, "Index out of bounds");
-};
+requires (Index <= 1u)
+struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {};
 
 
 } // namespace std
 } // namespace std
 
 

+ 7 - 6
src/entt/entity/view.hpp

@@ -2,6 +2,7 @@
 #define ENTT_ENTITY_VIEW_HPP
 #define ENTT_ENTITY_VIEW_HPP
 
 
 #include <array>
 #include <array>
+#include <concepts>
 #include <cstddef>
 #include <cstddef>
 #include <iterator>
 #include <iterator>
 #include <tuple>
 #include <tuple>
@@ -648,8 +649,8 @@ public:
      * @param other The storage for the type to combine the view with.
      * @param other The storage for the type to combine the view with.
      * @return A more specific view.
      * @return A more specific view.
      */
      */
-    template<typename OGet>
-    [[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>>> operator|(OGet &other) const noexcept {
+    template<std::derived_from<common_type> OGet>
+    [[nodiscard]] basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>> operator|(OGet &other) const noexcept {
         return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
         return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
     }
     }
 
 
@@ -660,7 +661,7 @@ public:
      * @param other The view to combine with.
      * @param other The view to combine with.
      * @return A more specific view.
      * @return A more specific view.
      */
      */
-    template<typename... OGet, typename... OExclude>
+    template<std::derived_from<common_type>... OGet, std::derived_from<common_type>... OExclude>
     [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
     [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
         return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
         return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
             *this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
             *this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
@@ -1105,8 +1106,8 @@ public:
      * @param other The storage for the type to combine the view with.
      * @param other The storage for the type to combine the view with.
      * @return A more specific view.
      * @return A more specific view.
      */
      */
-    template<typename OGet>
-    [[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get, OGet>, exclude_t<>>> operator|(OGet &other) const noexcept {
+    template<std::derived_from<common_type> OGet>
+    [[nodiscard]] basic_view<get_t<Get, OGet>, exclude_t<>> operator|(OGet &other) const noexcept {
         return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
         return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
     }
     }
 
 
@@ -1117,7 +1118,7 @@ public:
      * @param other The view to combine with.
      * @param other The view to combine with.
      * @return A more specific view.
      * @return A more specific view.
      */
      */
-    template<typename... OGet, typename... OExclude>
+    template<std::derived_from<common_type>... OGet, std::derived_from<common_type>... OExclude>
     [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
     [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
         return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
         return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
             *this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
             *this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});

+ 2 - 2
src/entt/graph/adjacency_matrix.hpp

@@ -1,6 +1,7 @@
 #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
 #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
 #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
 #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
 
 
+#include <concepts>
 #include <cstddef>
 #include <cstddef>
 #include <iterator>
 #include <iterator>
 #include <memory>
 #include <memory>
@@ -83,10 +84,9 @@ private:
  * @tparam Category Either a directed or undirected category tag.
  * @tparam Category Either a directed or undirected category tag.
  * @tparam Allocator Type of allocator used to manage memory and elements.
  * @tparam Allocator Type of allocator used to manage memory and elements.
  */
  */
-template<typename Category, typename Allocator>
+template<std::derived_from<directed_tag> Category, typename Allocator>
 class adjacency_matrix {
 class adjacency_matrix {
     using alloc_traits = std::allocator_traits<Allocator>;
     using alloc_traits = std::allocator_traits<Allocator>;
-    static_assert(std::is_base_of_v<directed_tag, Category>, "Invalid graph category");
     static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
     static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
     using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
     using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
 
 

+ 6 - 8
src/entt/graph/dot.hpp

@@ -1,8 +1,8 @@
 #ifndef ENTT_GRAPH_DOT_HPP
 #ifndef ENTT_GRAPH_DOT_HPP
 #define ENTT_GRAPH_DOT_HPP
 #define ENTT_GRAPH_DOT_HPP
 
 
+#include <concepts>
 #include <ostream>
 #include <ostream>
-#include <type_traits>
 #include "fwd.hpp"
 #include "fwd.hpp"
 
 
 namespace entt {
 namespace entt {
@@ -10,16 +10,14 @@ namespace entt {
 /**
 /**
  * @brief Outputs a graph in dot format.
  * @brief Outputs a graph in dot format.
  * @tparam Graph Graph type, valid as long as it exposes edges and vertices.
  * @tparam Graph Graph type, valid as long as it exposes edges and vertices.
- * @tparam Writer Vertex decorator type.
  * @param out A standard output stream.
  * @param out A standard output stream.
  * @param graph The graph to output.
  * @param graph The graph to output.
  * @param writer Vertex decorator object.
  * @param writer Vertex decorator object.
  */
  */
-template<typename Graph, typename Writer>
-void dot(std::ostream &out, const Graph &graph, Writer writer) {
-    static_assert(std::is_base_of_v<directed_tag, typename Graph::graph_category>, "Invalid graph category");
-
-    if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
+template<typename Graph>
+requires std::derived_from<typename Graph::graph_category, directed_tag>
+void dot(std::ostream &out, const Graph &graph, std::invocable<std::ostream &, typename Graph::vertex_type> auto writer) {
+    if constexpr(std::same_as<typename Graph::graph_category, undirected_tag>) {
         out << "graph{";
         out << "graph{";
     } else {
     } else {
         out << "digraph{";
         out << "digraph{";
@@ -32,7 +30,7 @@ void dot(std::ostream &out, const Graph &graph, Writer writer) {
     }
     }
 
 
     for(auto [lhs, rhs]: graph.edges()) {
     for(auto [lhs, rhs]: graph.edges()) {
-        if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
+        if constexpr(std::same_as<typename Graph::graph_category, undirected_tag>) {
             out << lhs << "--" << rhs << ";";
             out << lhs << "--" << rhs << ";";
         } else {
         } else {
             out << lhs << "->" << rhs << ";";
             out << lhs << "->" << rhs << ";";

+ 2 - 1
src/entt/graph/fwd.hpp

@@ -1,6 +1,7 @@
 #ifndef ENTT_GRAPH_FWD_HPP
 #ifndef ENTT_GRAPH_FWD_HPP
 #define ENTT_GRAPH_FWD_HPP
 #define ENTT_GRAPH_FWD_HPP
 
 
+#include <concepts>
 #include <cstddef>
 #include <cstddef>
 #include <memory>
 #include <memory>
 #include "../core/fwd.hpp"
 #include "../core/fwd.hpp"
@@ -13,7 +14,7 @@ struct directed_tag {};
 /*! @brief Directed graph category tag. */
 /*! @brief Directed graph category tag. */
 struct undirected_tag: directed_tag {};
 struct undirected_tag: directed_tag {};
 
 
-template<typename, typename = std::allocator<std::size_t>>
+template<std::derived_from<directed_tag>, typename = std::allocator<std::size_t>>
 class adjacency_matrix;
 class adjacency_matrix;
 
 
 template<typename = std::allocator<id_type>>
 template<typename = std::allocator<id_type>>

+ 10 - 7
src/entt/meta/factory.hpp

@@ -1,6 +1,7 @@
 #ifndef ENTT_META_FACTORY_HPP
 #ifndef ENTT_META_FACTORY_HPP
 #define ENTT_META_FACTORY_HPP
 #define ENTT_META_FACTORY_HPP
 
 
+#include <concepts>
 #include <cstddef>
 #include <cstddef>
 #include <cstdint>
 #include <cstdint>
 #include <functional>
 #include <functional>
@@ -208,15 +209,17 @@ public:
      * @return A meta factory for the parent type.
      * @return A meta factory for the parent type.
      */
      */
     template<typename Base>
     template<typename Base>
+    requires std::derived_from<Type, Base>
     meta_factory base() noexcept {
     meta_factory base() noexcept {
-        static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
-        auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
+        if constexpr(!std::same_as<Type, Base>) {
+            auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
 
 
-        base_type::insert_or_assign(
-            internal::meta_base_node{
-                type_id<Base>().hash(),
-                &internal::resolve<Base>,
-                op});
+            base_type::insert_or_assign(
+                internal::meta_base_node{
+                    type_id<Base>().hash(),
+                    &internal::resolve<Base>,
+                    op});
+        }
 
 
         return *this;
         return *this;
     }
     }

+ 2 - 2
src/entt/meta/node.hpp

@@ -43,15 +43,15 @@ enum class meta_traits : std::uint32_t {
 };
 };
 
 
 template<typename Type>
 template<typename Type>
+requires std::is_enum_v<Type>
 [[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
 [[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
-    static_assert(std::is_enum_v<Type>, "Invalid enum type");
     constexpr auto shift = std::popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
     constexpr auto shift = std::popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
     return Type{static_cast<std::underlying_type_t<Type>>(static_cast<std::underlying_type_t<meta_traits>>(traits) >> shift)};
     return Type{static_cast<std::underlying_type_t<Type>>(static_cast<std::underlying_type_t<meta_traits>>(traits) >> shift)};
 }
 }
 
 
 template<typename Type>
 template<typename Type>
+requires std::is_enum_v<Type>
 [[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
 [[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
-    static_assert(std::is_enum_v<Type>, "Invalid enum type");
     constexpr auto shift = std::popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
     constexpr auto shift = std::popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
     const auto traits = static_cast<std::underlying_type_t<internal::meta_traits>>(static_cast<std::underlying_type_t<Type>>(value));
     const auto traits = static_cast<std::underlying_type_t<internal::meta_traits>>(static_cast<std::underlying_type_t<Type>>(value));
     ENTT_ASSERT(traits < ((~static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
     ENTT_ASSERT(traits < ((~static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");

+ 7 - 3
src/entt/poly/poly.hpp

@@ -1,6 +1,7 @@
 #ifndef ENTT_POLY_POLY_HPP
 #ifndef ENTT_POLY_POLY_HPP
 #define ENTT_POLY_POLY_HPP
 #define ENTT_POLY_POLY_HPP
 
 
+#include <concepts>
 #include <cstddef>
 #include <cstddef>
 #include <functional>
 #include <functional>
 #include <tuple>
 #include <tuple>
@@ -48,20 +49,23 @@ class poly_vtable {
     using inspector = Concept::template type<poly_inspector>;
     using inspector = Concept::template type<poly_inspector>;
 
 
     template<typename Ret, typename Clazz, typename... Args>
     template<typename Ret, typename Clazz, typename... Args>
+    requires std::derived_from<inspector, std::remove_const_t<Clazz>>
     static auto vtable_entry(Ret (*)(Clazz &, Args...))
     static auto vtable_entry(Ret (*)(Clazz &, Args...))
-        -> std::enable_if_t<std::is_base_of_v<std::remove_const_t<Clazz>, inspector>, Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...)>;
+        -> Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...);
 
 
     template<typename Ret, typename... Args>
     template<typename Ret, typename... Args>
     static auto vtable_entry(Ret (*)(Args...))
     static auto vtable_entry(Ret (*)(Args...))
         -> Ret (*)(const basic_any<Len, Align> &, Args...);
         -> Ret (*)(const basic_any<Len, Align> &, Args...);
 
 
     template<typename Ret, typename Clazz, typename... Args>
     template<typename Ret, typename Clazz, typename... Args>
+    requires std::derived_from<inspector, Clazz>
     static auto vtable_entry(Ret (Clazz::*)(Args...))
     static auto vtable_entry(Ret (Clazz::*)(Args...))
-        -> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(basic_any<Len, Align> &, Args...)>;
+        -> Ret (*)(basic_any<Len, Align> &, Args...);
 
 
     template<typename Ret, typename Clazz, typename... Args>
     template<typename Ret, typename Clazz, typename... Args>
+    requires std::derived_from<inspector, Clazz>
     static auto vtable_entry(Ret (Clazz::*)(Args...) const)
     static auto vtable_entry(Ret (Clazz::*)(Args...) const)
-        -> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(const basic_any<Len, Align> &, Args...)>;
+        -> Ret (*)(const basic_any<Len, Align> &, Args...);
 
 
     template<auto... Candidate>
     template<auto... Candidate>
     static auto make_vtable(value_list<Candidate...>) noexcept
     static auto make_vtable(value_list<Candidate...>) noexcept

+ 2 - 1
src/entt/signal/delegate.hpp

@@ -27,7 +27,8 @@ auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
 template<typename Class, typename Ret, typename... Args, typename... Other>
 template<typename Class, typename Ret, typename... Args, typename... Other>
 auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
 auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
 
 
-template<typename Class, typename Type, typename... Other, typename = std::enable_if_t<std::is_member_object_pointer_v<Type Class::*>>>
+template<typename Class, typename Type, typename... Other>
+requires std::is_member_object_pointer_v<Type Class::*>
 auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
 auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
 
 
 template<typename... Type>
 template<typename... Type>