#include <cinttypes>
#include <type_traits>
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_integral_v<Id>, ""); (1)
static_assert(std::is_unsigned_v<Id>, "");
Value& operator[](Id id);
void push_back(const Value& value);
// class implementation left out
};
class entity {
public:
explicit entity(std::uint32_t id) : _id(id) {}
~entity() = default;
std::uint32_t id() const {
return _id;
}
operator std::uint32_t() const { (2)
return _id;
}
private:
std::uint32_t _id;
}; // class entity
int main() {
const auto e = entity{2};
auto set = sparse_set<entity, int>{};
set.push_back(0);
set.push_back(1);
set.push_back(2);
set.push_back(3);
auto i = set[e]; (3)
return 0;
}
I am trying to use a class with a conversion operator
to std::uint32_t
(2) as an index into a container class (3).
Accessing an element with an instance of that class works and i get the right element.
But testing the class with a static_assert
and std::is_unsigned_v
and std::is_integral_v
results in an assertion failure.
I need assertions to make sure Id
can be used as an index.
When I static_assert
with std::uint32_t
everything works so I would expect the conversion operator to work aswell.
CodePudding user response:
entity
certainly is not an integral type. It can be converted to a type that can be used as index and thats what you require:
#include <type_traits>
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_convertible_v<Id,size_t>, "");
// class implementation left out
};
CodePudding user response:
std::is_unsigned
and std::is_integral
only works for primitive types, it doesn't work for classes, even if they are implicitly convertible to a type they support. You can solve this by two ways:
Create your own trait:
#include <type_traits> // ... using uint16 = std::uint16_t; using uint32 = std::uint32_t; class entity { /* ... */ }; template <typename T> struct is_valid_index : std::is_unsigned<T> {}; template <> struct is_valid_index<entity> : std::true_type {}; template <typename T> constexpr auto is_valid_index_v = is_valid_index<T>::value; template<typename Id, typename Value> class sparse_set { static_assert(is_valid_index_v<Id>, ""); // ... }; // ...
Remove
std::is_unsigned
completely and usestd::is_convertible
instead:#include <type_traits> // ... using uint16 = std::uint16_t; using uint32 = std::uint32_t; class entity { /* ... */ }; template<typename Id, typename Value> class sparse_set { static_assert(std::is_convertible_v<Id, uint32>, ""); // ... }; // ...