1
#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;
}

我正在尝试使用带有conversion operatorto std::uint32_t(2) 的类作为容器类 (3) 的索引。使用该类的实例访问元素是可行的,我得到了正确的元素。

但是用static_assertandstd::is_unsigned_v和 and测试类std::is_integral_v会导致断言失败。

我需要断言以确保Id可以用作索引。

当我一切正常时static_assertstd::uint32_t我希望转换运算符也能正常工作。

4

2 回答 2

4

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

};
于 2021-09-21T11:05:11.140 回答
2

std::is_unsigned并且std::is_integral仅适用于原始类型,它不适用于类,即使它们可以隐式转换为它们支持的类型。您可以通过两种方式解决此问题:

  1. 创造你自己的特质:

    #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>, "");
        // ...
    };
    
    // ...
    
  2. 完全删除std::is_unsignedstd::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>, "");
        // ...
    };
    
    // ...
    
于 2021-09-21T11:08:48.113 回答