【问题标题】:C++ use class with conversion operator as index into arrayC ++使用带有转换运算符的类作为数组的索引
【发布时间】:2021-09-21 10:47:26
【问题描述】:
#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 operatorstd::uint32_t (2) 的类作为容器类 (3) 的索引。 使用该类的实例访问元素是可行的,我得到了正确的元素。

但是使用 static_assertstd::is_unsigned_vstd::is_integral_v 测试类会导致断言失败。

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

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

【问题讨论】:

  • entity (Id) 是整数类型吗?我不这么认为。
  • 不,static_assert(std::is_integral_v&lt;entity&gt;); 会抱怨。 "提供等于true的成员常量value,如果T的类型为boolcharchar8_t(C++20起),char16_t,@ 987654339@、wchar_tshortintlonglong long,或任何实现定义的扩展整数类型,包括任何有符号、无符号和 cv 限定的变体。否则,值等于false.”。另请注意:“is_integralis_integral_v(C++17 起)添加特化的程序的行为未定义。
  • 您的代码有几个与问题无关的错误。请修复它们并添加必要的包含

标签: c++ conversion-operator array-indexing


【解决方案1】:

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

};

【讨论】:

    【解决方案2】:

    std::is_unsignedstd::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_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>, "");
          // ...
      };
      
      // ...
      

    【讨论】:

    • 不是is_unsigned 也不是is_convertible_v&lt;T,uint32&gt; 吗?
    猜你喜欢
    • 2011-03-18
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    相关资源
    最近更新 更多