在C++中是否可以声明具有固定位宽的类型,而不使用结构体?

huangapple go评论95阅读模式
英文:

Is it possible to declare a type with a set bit width in c++ without using a struct?

问题

C++中是否支持不使用struct、class或union位域来指定类型的位宽?使用它们会增加不必要且让人讨厌的间接性级别。

如果C++有类似C#的属性,你可以将Address设置为一个访问器,隐藏掉这种间接性。在Ada中,你可以这样声明Address

  1. type Address is range 0..2**4 - 1 with Object_Size = 4; -- 这不是很可爱吗!

我尝试了以下声明,理论上应该能工作:

  1. typedef unsigned char Address:4; // 如果我们有这么幸运的话!

C++是否支持这样的构造或解决方法?

英文:

It's been at least a decade since I last touched C++. Supposedly, C++ has had a minor overhaul. Is there a way to specify the bit width of a type without using struct, class, or union bitfields? The problem with them is that it adds an unnecessary and annoying level of indirection:

  1. struct Address
  2. {
  3. unsigned char val:4 = 0; // C++ in 2020?
  4. };
  5. struct Device
  6. {
  7. Address address; // 4-bit address
  8. string name;
  9. };
  10. int main()
  11. {
  12. Device device;
  13. device.address.val = 0x8; // Yuckity yuck WTF!
  14. return 0;
  15. };

If C++ had properties like C#, you could make Address an accessor that hides away the indirection. In Ada, you would simply declare Address like so:

  1. type Address is range 0..2**4 - 1 with Object_Size = 4; -- Isn't this cute and sweet!

I tried the following declaration and there's no reason why it shouldn't work:

  1. typedef unsigned char Address:4; // if we were only so lucky!

Does C++ support such a construct or workaround?

答案1

得分: 1

以下是您提供的代码的翻译部分:

  1. 不是开箱即用的,但制作一个小的包装类来进行验证并不难。这里是这种类的草图,甚至可以在编译时进行检查。
  2. 演示链接:https://onlinegdb.com/RBVQfsAI5
  3. #include <iostream>
  4. // N是您想要使用的地址位数
  5. template<std::size_t N>
  6. struct address_t
  7. {
  8. public:
  9. explicit constexpr address_t(std::uintptr_t value) :
  10. address{ checked_value(value) }
  11. {
  12. }
  13. // 这是少数情况下隐式转换有用的地方
  14. operator std::uintptr_t() const noexcept
  15. {
  16. return address;
  17. }
  18. // 赋值运算符检查值。
  19. void operator=(std::uintptr_t value)
  20. {
  21. address = checked_value(value);
  22. }
  23. private:
  24. constexpr std::uintptr_t checked_value(std::uintptr_t value)
  25. {
  26. if (value >= (1 << N)) throw std::invalid_argument("地址值过大");
  27. return value;
  28. }
  29. std::uintptr_t address;
  30. };
  31. int main()
  32. {
  33. // addres_t<4> 表示最多有 4 位的地址
  34. static constexpr address_t<4> compile_time_address{15}; // 如果值过大,将无法编译通过
  35. std::cout << compile_time_address << "\n"; // 使用隐式转换到 std::uint_ptr_t
  36. address_t<4> runtime_address{15};
  37. std::cout << runtime_address << "\n";
  38. runtime_address = 12;
  39. std::cout << runtime_address << "\n";
  40. try
  41. {
  42. // 在运行时分配无效值会抛出异常。
  43. address_t<4> runtime_address_fail{16};
  44. }
  45. catch (const std::invalid_argument&)
  46. {
  47. }
  48. return 0;
  49. }

请注意,翻译只包括代码部分,不包括问题或其他内容。如果您需要进一步的帮助,请随时提问。

英文:

Not out of the box, but it is not so hard to make a small wrapper class that does the validation. Sketch of such a class here, it can even check at compile time.

Demo here : https://onlinegdb.com/RBVQfsAI5

  1. #include &lt;iostream&gt;
  2. // N is the number of address bits you want to use
  3. template&lt;std::size_t N&gt;
  4. struct address_t
  5. {
  6. public:
  7. explicit constexpr address_t(std::uintptr_t value) :
  8. address{ checked_value(value) }
  9. {
  10. }
  11. // one of the rare cases implicit conversion is useful
  12. operator std::uintptr_t() const noexcept
  13. {
  14. return address;
  15. }
  16. // assigment operator checks the value.
  17. void operator=(std::uintptr_t value)
  18. {
  19. address = checked_value(value);
  20. }
  21. private:
  22. constexpr std::uintptr_t checked_value(std::uintptr_t value)
  23. {
  24. if (value &gt;= (1 &lt;&lt; N)) throw std::invalid_argument(&quot;address value too large&quot;);
  25. return value;
  26. }
  27. std::uintptr_t address;
  28. };
  29. int main()
  30. {
  31. //addres_t&lt;4&gt; means an address with max. 4 bits
  32. static constexpr address_t&lt;4&gt; compile_time_address{15}; // will not compile if value too big
  33. std::cout &lt;&lt; compile_time_address &lt;&lt; &quot;\n&quot;; // uses implicit conversion to std::uint_ptr_t
  34. address_t&lt;4&gt; runtime_address{15};
  35. std::cout &lt;&lt; runtime_address &lt;&lt; &quot;\n&quot;;
  36. runtime_address = 12;
  37. std::cout &lt;&lt; runtime_address &lt;&lt; &quot;\n&quot;;
  38. try
  39. {
  40. // at runtime assigning an invalid value will throw.
  41. address_t&lt;4&gt; runtime_address_fail{16};
  42. }
  43. catch (const std::invalid_argument&amp;)
  44. {
  45. }
  46. return 0;
  47. }

huangapple
  • 本文由 发表于 2023年6月29日 14:43:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76578614.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定