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

*: added meaningful messages (?) to static asserts (close #493)

Michele Caini 5 лет назад
Родитель
Сommit
5fbb663529

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

@@ -80,7 +80,7 @@ struct insertion_sort {
  */
 template<std::size_t Bit, std::size_t N>
 struct radix_sort {
-    static_assert((N % Bit) == 0);
+    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.

+ 1 - 1
src/entt/core/ident.hpp

@@ -46,7 +46,7 @@ class identifier {
 
     template<typename Type, std::size_t... Indexes>
     static constexpr id_type get(std::index_sequence<Indexes...>) {
-        static_assert(std::disjunction_v<std::is_same<Type, Types>...>);
+        static_assert(std::disjunction_v<std::is_same<Type, Types>...>, "Invalid type");
         return (0 + ... + (std::is_same_v<Type, std::tuple_element_t<Indexes, tuple_type>> ? id_type(Indexes) : id_type{}));
     }
 

+ 1 - 1
src/entt/core/type_traits.hpp

@@ -193,7 +193,7 @@ inline constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::v
  */
 template<typename Member>
 class member_class {
-    static_assert(std::is_member_pointer_v<Member>);
+    static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
 
     template<typename Class, typename Ret, typename... Args>
     static Class * clazz(Ret(Class:: *)(Args...));

+ 2 - 2
src/entt/entity/group.hpp

@@ -385,7 +385,7 @@ public:
     template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
     void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
         if constexpr(sizeof...(Component) == 0) {
-            static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>);
+            static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
             handler->sort(handler->begin(), handler->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
         }  else if constexpr(sizeof...(Component) == 1) {
             handler->sort(handler->begin(), handler->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
@@ -812,7 +812,7 @@ public:
         auto *cpool = std::get<0>(pools);
 
         if constexpr(sizeof...(Component) == 0) {
-            static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>);
+            static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
             cpool->sort(cpool->end()-*length, cpool->end(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
         } else if constexpr(sizeof...(Component) == 1) {
             cpool->sort(cpool->end()-*length, cpool->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {

+ 1 - 1
src/entt/entity/helper.hpp

@@ -122,7 +122,7 @@ as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>
  */
 template<auto Member, typename Entity = entity>
 void invoke(basic_registry<Entity> &reg, const Entity entt) {
-    static_assert(std::is_member_function_pointer_v<decltype(Member)>);
+    static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
     delegate<void(basic_registry<Entity> &, const Entity)> func;
     func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
     func(reg, entt);

+ 1 - 3
src/entt/entity/observer.hpp

@@ -257,7 +257,7 @@ class basic_observer {
 
     template<typename... Matcher, std::size_t... Index>
     void connect(basic_registry<Entity> &reg, std::index_sequence<Index...>) {
-        static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits);
+        static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits, "Too many matchers");
         (matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
         release = &basic_observer::disconnect<Matcher...>;
     }
@@ -408,8 +408,6 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        static_assert(std::is_invocable_v<Func, entity_type>);
-
         for(const auto entity: *this) {
             func(entity);
         }

+ 9 - 15
src/entt/entity/registry.hpp

@@ -45,7 +45,7 @@ class basic_registry {
 
     template<typename Component>
     struct pool_handler final: storage<Entity, Component> {
-        static_assert(std::is_same_v<Component, std::decay_t<Component>>);
+        static_assert(std::is_same_v<Component, std::decay_t<Component>>, "Invalid component type");
         std::size_t super{};
 
         auto on_construct() ENTT_NOEXCEPT {
@@ -129,12 +129,11 @@ class basic_registry {
 
     template<typename... Exclude, typename... Get, typename... Owned>
     struct group_handler<exclude_t<Exclude...>, get_t<Get...>, Owned...> {
-        static_assert(std::conjunction_v<std::is_same<Owned, std::decay_t<Owned>>..., std::is_same<Get, std::decay_t<Get>>..., std::is_same<Exclude, std::decay_t<Exclude>>...>);
+        static_assert(std::conjunction_v<std::is_same<Owned, std::decay_t<Owned>>..., std::is_same<Get, std::decay_t<Get>>..., std::is_same<Exclude, std::decay_t<Exclude>>...>, "One or more component types are invalid");
         std::conditional_t<sizeof...(Owned) == 0, sparse_set<Entity>, std::size_t> current{};
 
         template<typename Component>
         void maybe_valid_if(basic_registry &owner, const Entity entt) {
-            static_assert(std::disjunction_v<std::is_same<Owned, std::decay_t<Owned>>..., std::is_same<Get, std::decay_t<Get>>..., std::is_same<Exclude, std::decay_t<Exclude>>...>);
             [[maybe_unused]] const auto cpools = std::forward_as_tuple(owner.assure<Owned>()...);
 
             const auto is_valid = ((std::is_same_v<Component, Owned> || std::get<pool_handler<Owned> &>(cpools).contains(entt)) && ...)
@@ -182,7 +181,6 @@ class basic_registry {
 
     template<typename Component>
     const pool_handler<Component> & assure() const {
-        static_assert(std::is_same_v<Component, std::decay_t<Component>>);
         const sparse_set<entity_type> *cpool;
 
         if constexpr(has_type_index_v<Component>) {
@@ -674,7 +672,7 @@ public:
      */
     template<typename Component, typename EIt, typename CIt>
     void insert(EIt first, EIt last, CIt from, CIt to) {
-        static_assert(std::is_constructible_v<Component, typename std::iterator_traits<CIt>::value_type>);
+        static_assert(std::is_constructible_v<Component, typename std::iterator_traits<CIt>::value_type>, "Invalid value type");
         ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }));
         assure<Component>().insert(*this, first, last, from, to);
     }
@@ -1035,8 +1033,6 @@ public:
      */
     template<typename Func>
     void each(Func func) const {
-        static_assert(std::is_invocable_v<Func, entity_type>);
-
         if(destroyed == null) {
             for(auto pos = entities.size(); pos; --pos) {
                 func(entities[pos-1]);
@@ -1078,8 +1074,6 @@ public:
      */
     template<typename Func>
     void orphans(Func func) const {
-        static_assert(std::is_invocable_v<Func, entity_type>);
-
         each([this, &func](const auto entity) {
             if(orphan(entity)) {
                 func(entity);
@@ -1296,14 +1290,14 @@ public:
      */
     template<typename... Component, typename... Exclude>
     entt::basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) const {
-        static_assert(sizeof...(Component) > 0);
+        static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
         return { assure<std::decay_t<Component>>()..., assure<Exclude>()... };
     }
 
     /*! @copydoc view */
     template<typename... Component, typename... Exclude>
     entt::basic_view<Entity, exclude_t<Exclude...>, Component...> view(exclude_t<Exclude...> = {}) {
-        static_assert(sizeof...(Component) > 0);
+        static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported");
         return { assure<std::decay_t<Component>>()..., assure<Exclude>()... };
     }
 
@@ -1347,8 +1341,8 @@ public:
      */
     template<typename... Owned, typename... Get, typename... Exclude>
     entt::basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> group(get_t<Get...>, exclude_t<Exclude...> = {}) {
-        static_assert(sizeof...(Owned) + sizeof...(Get) > 0);
-        static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1);
+        static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only views are not supported");
+        static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed");
 
         using handler_type = group_handler<exclude_t<Exclude...>, get_t<std::decay_t<Get>...>, std::decay_t<Owned>...>;
 
@@ -1443,7 +1437,7 @@ public:
      */
     template<typename... Owned, typename... Get, typename... Exclude>
     entt::basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> group(get_t<Get...>, exclude_t<Exclude...> = {}) const {
-        static_assert(std::conjunction_v<std::is_const<Owned>..., std::is_const<Get>...>);
+        static_assert(std::conjunction_v<std::is_const<Owned>..., std::is_const<Get>...>, "Invalid non-const type");
         return const_cast<basic_registry *>(this)->group<Owned...>(entt::get<Get...>, exclude<Exclude...>);
     }
 
@@ -1472,7 +1466,7 @@ public:
      */
     template<typename... Owned, typename... Exclude>
     entt::basic_group<Entity, exclude_t<Exclude...>, get_t<>, Owned...> group(exclude_t<Exclude...> = {}) const {
-        static_assert(std::conjunction_v<std::is_const<Owned>...>);
+        static_assert(std::conjunction_v<std::is_const<Owned>...>, "Invalid non-const type");
         return const_cast<basic_registry *>(this)->group<Owned...>(exclude<Exclude...>);
     }
 

+ 2 - 2
src/entt/entity/snapshot.hpp

@@ -336,7 +336,7 @@ class basic_continuous_loader {
             } else if constexpr(std::is_same_v<first_type, entity_type>) {
                 other.emplace(map(pair.first), std::move(pair.second));
             } else {
-                static_assert(std::is_same_v<second_type, entity_type>);
+                static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
                 other.emplace(std::move(pair.first), map(pair.second));
             }
         }
@@ -348,7 +348,7 @@ class basic_continuous_loader {
     auto update(char, Container &container)
     -> decltype(typename Container::value_type{}, void()) {
         // vector like container
-        static_assert(std::is_same_v<typename Container::value_type, entity_type>);
+        static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
 
         for(auto &&entt: container) {
             entt = map(entt);

+ 1 - 1
src/entt/entity/sparse_set.hpp

@@ -41,7 +41,7 @@ namespace entt {
  */
 template<typename Entity>
 class sparse_set {
-    static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0));
+    static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two");
     static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(Entity);
 
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;

+ 1 - 2
src/entt/entity/storage.hpp

@@ -46,8 +46,7 @@ namespace entt {
  */
 template<typename Entity, typename Type, typename = std::void_t<>>
 class storage: public sparse_set<Entity> {
-    static_assert(std::is_move_constructible_v<Type>);
-    static_assert(std::is_move_assignable_v<Type>);
+    static_assert(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>, "The managed type must be at least move constructible and assignable");
 
     using underlying_type = sparse_set<Entity>;
     using traits_type = entt_traits<std::underlying_type_t<Entity>>;

+ 2 - 2
src/entt/entity/view.hpp

@@ -405,7 +405,7 @@ public:
         ENTT_ASSERT(contains(entt));
 
         if constexpr(sizeof...(Comp) == 0) {
-            static_assert(sizeof...(Component) == 1);
+            static_assert(sizeof...(Component) == 1, "Invalid component type");
             return (std::get<pool_type<Component> *>(pools)->get(entt), ...);
         } else if constexpr(sizeof...(Comp) == 1) {
             return (std::get<pool_type<Comp> *>(pools)->get(entt), ...);
@@ -672,7 +672,7 @@ public:
      */
     template<typename Comp = Component>
     decltype(auto) get(const entity_type entt) const {
-        static_assert(std::is_same_v<Comp, Component>);
+        static_assert(std::is_same_v<Comp, Component>, "Invalid component type");
         ENTT_ASSERT(contains(entt));
         return pool->get(entt);
     }

+ 14 - 16
src/entt/meta/factory.hpp

@@ -96,7 +96,7 @@ bool setter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index,
         if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
             using helper_type = meta_function_helper_t<decltype(Data)>;
             using data_type = std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
-            static_assert(std::is_invocable_v<decltype(Data), Type &, data_type>);
+            static_assert(std::is_invocable_v<decltype(Data), Type &, data_type>, "Invalid function or member function");
             auto * const clazz = instance.try_cast<Type>();
             auto * const direct = value.try_cast<data_type>();
 
@@ -106,7 +106,7 @@ bool setter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index,
             }
         } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
             using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
-            static_assert(std::is_invocable_v<decltype(Data), Type *>);
+            static_assert(std::is_invocable_v<decltype(Data), Type *>, "Invalid data member");
             auto * const clazz = instance.try_cast<Type>();
 
             if constexpr(std::is_array_v<data_type>) {
@@ -127,7 +127,7 @@ bool setter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index,
                 }
             }
         } else {
-            static_assert(std::is_pointer_v<decltype(Data)>);
+            static_assert(std::is_pointer_v<decltype(Data)>, "Invalid pointer to data type");
             using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
 
             if constexpr(std::is_array_v<data_type>) {
@@ -162,18 +162,18 @@ meta_any getter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any in
         } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
             return meta_any{std::ref(std::forward<decltype(value)>(value))};
         } else {
-            static_assert(std::is_same_v<Policy, as_is_t>);
+            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
             return meta_any{std::forward<decltype(value)>(value)};
         }
     };
 
     if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
-        static_assert(std::is_invocable_v<decltype(Data), Type &>);
+        static_assert(std::is_invocable_v<decltype(Data), Type &>, "Invalid function or member function");
         auto * const clazz = instance.try_cast<Type>();
         return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
     } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
         using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
-        static_assert(std::is_invocable_v<decltype(Data), Type *>);
+        static_assert(std::is_invocable_v<decltype(Data), Type *>, "Invalid data member");
         auto * const clazz = instance.try_cast<Type>();
 
         if constexpr(std::is_array_v<data_type>) {
@@ -183,7 +183,7 @@ meta_any getter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any in
             return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
         }
     } else {
-        static_assert(std::is_pointer_v<std::decay_t<decltype(Data)>>);
+        static_assert(std::is_pointer_v<std::decay_t<decltype(Data)>>, "Invalid pointer to data type");
 
         if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
             auto * const idx = index.try_cast<std::size_t>();
@@ -206,7 +206,7 @@ meta_any invoke([[maybe_unused]] meta_any instance, meta_any *args, std::index_s
         } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
             return meta_any{std::ref(std::invoke(Candidate, *params...))};
         } else {
-            static_assert(std::is_same_v<Policy, as_is_t>);
+            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
             return meta_any{std::invoke(Candidate, *params...)};
         }
     };
@@ -402,7 +402,6 @@ public:
         return meta_factory<Type, Type>{&node->prop};
     }
 
-    /*! @copydoc type */
     /**
      * @brief Assigns a meta base to a meta type.
      *
@@ -413,7 +412,7 @@ public:
      */
     template<typename Base>
     auto base() ENTT_NOEXCEPT {
-        static_assert(std::is_base_of_v<Base, Type>);
+        static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_base_node node{
@@ -443,7 +442,7 @@ public:
      */
     template<typename To>
     auto conv() ENTT_NOEXCEPT {
-        static_assert(std::is_convertible_v<Type, To>);
+        static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_conv_node node{
@@ -511,7 +510,7 @@ public:
     template<auto Func, typename Policy = as_is_t>
     auto ctor() ENTT_NOEXCEPT {
         using helper_type = internal::meta_function_helper_t<decltype(Func)>;
-        static_assert(std::is_same_v<typename helper_type::return_type, Type>);
+        static_assert(std::is_same_v<typename helper_type::return_type, Type>, "The function doesn't return an object of the required type");
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_ctor_node node{
@@ -583,7 +582,7 @@ public:
      */
     template<auto Func>
     auto dtor() ENTT_NOEXCEPT {
-        static_assert(std::is_invocable_v<decltype(Func), Type &>);
+        static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_dtor_node node{
@@ -620,7 +619,7 @@ public:
         internal::meta_data_node *curr = nullptr;
 
         if constexpr(std::is_same_v<Type, decltype(Data)>) {
-            static_assert(std::is_same_v<Policy, as_is_t>);
+            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
 
             static internal::meta_data_node node{
                 {},
@@ -652,7 +651,6 @@ public:
 
             curr = &node;
         } else {
-            static_assert(std::is_pointer_v<std::decay_t<decltype(Data)>>);
             using data_type = std::remove_pointer_t<std::decay_t<decltype(Data)>>;
 
             static internal::meta_data_node node{
@@ -702,7 +700,7 @@ public:
     template<auto Setter, auto Getter, typename Policy = as_is_t>
     auto data(const id_type id) ENTT_NOEXCEPT {
         using underlying_type = std::invoke_result_t<decltype(Getter), Type &>;
-        static_assert(std::is_invocable_v<decltype(Setter), Type &, underlying_type>);
+        static_assert(std::is_invocable_v<decltype(Setter), Type &, underlying_type>, "Invalid setter and/or getter");
         auto * const type = internal::meta_info<Type>::resolve();
 
         static internal::meta_data_node node{

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

@@ -222,7 +222,7 @@ struct ENTT_API meta_context {
 
 template<typename Type>
 struct ENTT_API meta_node {
-    static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>);
+    static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
 
     static meta_type_node * resolve() ENTT_NOEXCEPT {
         static meta_type_node node{
@@ -670,7 +670,7 @@ struct meta_handle {
         if constexpr(std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_any>) {
             any = *value;
         } else {
-            static_assert(std::is_lvalue_reference_v<Type>);
+            static_assert(std::is_lvalue_reference_v<Type>, "Lvalue reference required");
             any = std::ref(value);
         }
     }

+ 1 - 1
src/entt/process/process.hpp

@@ -169,7 +169,7 @@ public:
 
     /*! @brief Default destructor. */
     virtual ~process() {
-        static_assert(std::is_base_of_v<process, Derived>);
+        static_assert(std::is_base_of_v<process, Derived>, "Incorrect use of the class template");
     }
 
     /**

+ 2 - 2
src/entt/process/scheduler.hpp

@@ -63,7 +63,7 @@ class scheduler {
 
         template<typename Proc, typename... Args>
         continuation then(Args &&... args) {
-            static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>);
+            static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
             auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &scheduler::deleter<Proc>};
             handler->next.reset(new process_handler{std::move(proc), &scheduler::update<Proc>, &scheduler::abort<Proc>, nullptr});
             handler = handler->next.get();
@@ -175,7 +175,7 @@ public:
      */
     template<typename Proc, typename... Args>
     auto attach(Args &&... args) {
-        static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>);
+        static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
         auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &scheduler::deleter<Proc>};
         process_handler handler{std::move(proc), &scheduler::update<Proc>, &scheduler::abort<Proc>, nullptr};
         // forces the process to exit the uninitialized state

+ 1 - 1
src/entt/resource/cache.hpp

@@ -92,7 +92,7 @@ struct cache {
      */
     template<typename Loader, typename... Args>
     entt::handle<Resource> load(const id_type id, Args &&... args) {
-        static_assert(std::is_base_of_v<loader<Loader, Resource>, Loader>);
+        static_assert(std::is_base_of_v<loader<Loader, Resource>, Loader>, "Invalid loader type");
         entt::handle<Resource> resource{};
 
         if(auto it = resources.find(id); it == resources.cend()) {

+ 1 - 1
src/entt/signal/dispatcher.hpp

@@ -84,7 +84,7 @@ class dispatcher {
 
     template<typename Event>
     pool_handler<Event> & assure() {
-        static_assert(std::is_same_v<Event, std::decay_t<Event>>);
+        static_assert(std::is_same_v<Event, std::decay_t<Event>>, "Invalid event type");
 
         if constexpr(has_type_index_v<Event>) {
             const auto index = type_index<Event>::value();

+ 2 - 2
src/entt/signal/emitter.hpp

@@ -126,7 +126,7 @@ class emitter {
 
     template<typename Event>
     const pool_handler<Event> & assure() const {
-        static_assert(std::is_same_v<Event, std::decay_t<Event>>);
+        static_assert(std::is_same_v<Event, std::decay_t<Event>>, "Invalid event type");
 
         if constexpr(has_type_index_v<Event>) {
             const auto index = type_index<Event>::value();
@@ -187,7 +187,7 @@ public:
 
     /*! @brief Default destructor. */
     virtual ~emitter() {
-        static_assert(std::is_base_of_v<emitter<Derived>, Derived>);
+        static_assert(std::is_base_of_v<emitter<Derived>, Derived>, "Incorrect use of the class template");
     }
 
     /*! @brief Default move constructor. */