C++ 使用 class 和转换运算符作为数组的索引
C++ use class with conversion operator as index into array
#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;
}
我正在尝试使用 class 和 conversion operator
到 std::uint32_t
(2) 作为容器 class (3) 的索引。
使用 class 的实例访问元素有效,我得到了正确的元素。
但是用 static_assert
和 std::is_unsigned_v
和 std::is_integral_v
测试 class 会导致断言失败。
我需要断言来确保 Id
可以用作索引。
当我 static_assert
和 std::uint32_t
一切正常时,我希望转换运算符也能正常工作。
entity
当然不是整型。它可以转换为可用作索引的类型,这就是您所需要的:
#include <type_traits>
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_convertible_v<Id,size_t>, "");
// class implementation left out
};
std::is_unsigned
和 std::is_integral
仅适用于基本类型,不适用于 类,即使它们可以隐式转换为它们支持的类型。您可以通过两种方式解决这个问题:
创建你自己的特质:
#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>, "");
// ...
};
// ...
完全删除 std::is_unsigned
并改用 std::is_convertible
:
#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>, "");
// ...
};
// ...
#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;
}
我正在尝试使用 class 和 conversion operator
到 std::uint32_t
(2) 作为容器 class (3) 的索引。
使用 class 的实例访问元素有效,我得到了正确的元素。
但是用 static_assert
和 std::is_unsigned_v
和 std::is_integral_v
测试 class 会导致断言失败。
我需要断言来确保 Id
可以用作索引。
当我 static_assert
和 std::uint32_t
一切正常时,我希望转换运算符也能正常工作。
entity
当然不是整型。它可以转换为可用作索引的类型,这就是您所需要的:
#include <type_traits>
template<typename Id, typename Value>
class sparse_set {
static_assert(std::is_convertible_v<Id,size_t>, "");
// class implementation left out
};
std::is_unsigned
和 std::is_integral
仅适用于基本类型,不适用于 类,即使它们可以隐式转换为它们支持的类型。您可以通过两种方式解决这个问题:
创建你自己的特质:
#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>, ""); // ... }; // ...
完全删除
std::is_unsigned
并改用std::is_convertible
:#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>, ""); // ... }; // ...