如何将枚举变量传递给具有枚举模板特化的结构体

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

How to pass a enum variable to a struct with template specialization for enum

问题

我设计了一个带有模板特化的结构体,用于枚举类型,如下所示:

  1. template<DataType type>
  2. struct TypeTrait;
  3. template<>
  4. struct TypeTrait<DATA_TYPE_INT8> {
  5. static constexpr uint32_t size = sizeof(int8_t);
  6. };
  7. template<>
  8. struct TypeTrait<DATA_TYPE_INT16> {
  9. static constexpr uint32_t size = sizeof(int16_t);
  10. };
  11. template<>
  12. struct TypeTrait<DATA_TYPE_FP16> {
  13. static constexpr uint32_t size = sizeof(uint16_t);
  14. };
  15. template<>
  16. struct TypeTrait<DATA_TYPE_UINT8> {
  17. static constexpr uint32_t size = sizeof(uint8_t);
  18. };
  19. template<>
  20. struct TypeTrait<DATA_TYPE_UINT16> {
  21. static constexpr uint32_t size = sizeof(uint16_t);
  22. };
  23. template<>
  24. struct TypeTrait<DATA_TYPE_INT32> {
  25. static constexpr uint32_t size = sizeof(int32_t);
  26. };
  27. template<>
  28. struct TypeTrait<DATA_TYPE_UINT32> {
  29. static constexpr uint32_t size = sizeof(uint32_t);
  30. };
  31. template<>
  32. struct TypeTrait<DATA_TYPE_FP32> {
  33. static constexpr uint32_t size = sizeof(float);
  34. };

枚举类型 DataType 定义如下:

  1. enum DataType {
  2. DATA_TYPE_INT8 = 0,
  3. DATA_TYPE_INT16 = 1,
  4. DATA_TYPE_FP16 = 2,
  5. DATA_TYPE_UINT8 = 3,
  6. DATA_TYPE_UINT16 = 4,
  7. DATA_TYPE_INT32 = 5,
  8. DATA_TYPE_UINT32 = 6,
  9. DATA_TYPE_FP32 = 7,
  10. DATA_TYPE_UNKNOWN
  11. };

我想要将一个 DataType 变量传递给 TypeTrait 结构体,如下所示:

  1. class Test {
  2. public:
  3. ...
  4. void Convert() {
  5. ...
  6. uint32_t size = TypeTrait<type_>::size;
  7. ...
  8. }
  9. private:
  10. DataType type_;
  11. };

当我这样做时,在编译程序时出现了问题:

  1. main.cc: In member function void Test::Convert():
  2. main.cc:63:35: error: use of this in a constant expression
  3. 63 | uint32_t size = TypeTrait<type_>::size;
  4. | ^~~~~
  5. main.cc:63:40: error: use of this in a constant expression
  6. 63 | uint32_t size = TypeTrait<type_>::size;
  7. | ^
  8. main.cc:63:35: note: in template argument for type DataType
  9. 63 | uint32_t size = TypeTrait<type_>::size;
  10. | ^~~~~

我尝试了许多方法,例如将 type_ 转换为常量值,如下所示:

  1. const DataType dataType = type_;
  2. uint32_t size = TypeTrait<dataType>::size;

然后出现了这个问题:

  1. main.cc: In member function void Test::Convert():
  2. main.cc:63:39: error: the value of type is not usable in a constant expression
  3. 63 | uint32_t size = TypeTrait<type>::size;
  4. | ^
  5. main.cc:62:24: note: type was not initialized with a constant expression
  6. 62 | const DataType type = GetType();
  7. | ^~~~
  8. main.cc:63:39: note: in template argument for type DataType
  9. 63 | uint32_t size = TypeTrait<type>::size;
  10. |

我知道如果我像这样传递枚举元素,程序就不会出问题:

  1. uint32_t size = TypeTrait<DataType::DATA_TYPE_UINT32>::size;

我不知道如何解决这个问题。所以我必须使用 switch 语句来处理这个问题,这违背了我的愿望。我只是想在我的代码中删除 switch 语句。要重构的代码如下:

  1. switch (dataType_) {
  2. case DATA_TYPE_INT8:
  3. byteSize = elemCnt * sizeof(int8_t);
  4. break;
  5. case DATA_TYPE_INT16:
  6. byteSize = elemCnt * sizeof(int16_t);
  7. break;
  8. case DATA_TYPE_FP16:
  9. byteSize = elemCnt * sizeof(uint16_t);
  10. break;
  11. case DATA_TYPE_UINT8:
  12. byteSize = elemCnt * sizeof(uint8_t);
  13. break;
  14. case DATA_TYPE_UINT16:
  15. byteSize = elemCnt * sizeof(uint16_t);
  16. break;
  17. case DATA_TYPE_INT32:
  18. byteSize = elemCnt * sizeof(int32_t);
  19. break;
  20. case DATA_TYPE_UINT32:
  21. byteSize = elemCnt * sizeof(uint32_t);
  22. break;
  23. case DATA_TYPE_FP32:
  24. byteSize = elemCnt * sizeof(float);
  25. break;
  26. }
英文:

I design a struct with template specialization for enum, like this:

  1. template&lt;DataType type&gt;
  2. struct TypeTrait;
  3. template&lt;&gt;
  4. struct TypeTrait&lt;DATA_TYPE_INT8&gt; {
  5. static constexpr uint32_t size = sizeof(int8_t);
  6. };
  7. template&lt;&gt;
  8. struct TypeTrait&lt;DATA_TYPE_INT16&gt; {
  9. static constexpr uint32_t size = sizeof(int16_t);
  10. };
  11. template&lt;&gt;
  12. struct TypeTrait&lt;DATA_TYPE_FP16&gt; {
  13. static constexpr uint32_t size = sizeof(uint16_t);
  14. };
  15. template&lt;&gt;
  16. struct TypeTrait&lt;DATA_TYPE_UINT8&gt; {
  17. static constexpr uint32_t size = sizeof(uint8_t);
  18. };
  19. template&lt;&gt;
  20. struct TypeTrait&lt;DATA_TYPE_UINT16&gt; {
  21. static constexpr uint32_t size = sizeof(uint16_t);
  22. };
  23. template&lt;&gt;
  24. struct TypeTrait&lt;DATA_TYPE_INT32&gt; {
  25. static constexpr uint32_t size = sizeof(int32_t);
  26. };
  27. template&lt;&gt;
  28. struct TypeTrait&lt;DATA_TYPE_UINT32&gt; {
  29. static constexpr uint32_t size = sizeof(uint32_t);
  30. };
  31. template&lt;&gt;
  32. struct TypeTrait&lt;DATA_TYPE_FP32&gt; {
  33. static constexpr uint32_t size = sizeof(float);
  34. };

enum DataType is defined like this:

  1. enum DataType {
  2. DATA_TYPE_INT8 = 0,
  3. DATA_TYPE_INT16 = 1,
  4. DATA_TYPE_FP16 = 2,
  5. DATA_TYPE_UINT8 = 3,
  6. DATA_TYPE_UINT16 = 4,
  7. DATA_TYPE_INT32 = 5,
  8. DATA_TYPE_UINT32 = 6,
  9. DATA_TYPE_FP32 = 7,
  10. DATA_TYPE_UNKOWN
  11. };

And I want pass a DataType variable to struct TypeTrait, like this:

  1. class Test {
  2. public:
  3. ...
  4. void Convert() {
  5. ...
  6. uint32_t size = TypeTrait&lt;type_&gt;::size;
  7. ...
  8. }
  9. private:
  10. DataType type_;
  11. };

When I do this, there is a problem while compiling my program:

  1. main.cc: In member function void Test::Convert()’:
  2. main.cc:63:35: error: use of this in a constant expression
  3. 63 | uint32_t size = TypeTrait&lt;type_&gt;::size;
  4. | ^~~~~
  5. main.cc:63:40: error: use of this in a constant expression
  6. 63 | uint32_t size = TypeTrait&lt;type_&gt;::size;
  7. | ^
  8. main.cc:63:35: note: in template argument for type DataType
  9. 63 | uint32_t size = TypeTrait&lt;type_&gt;::size;
  10. | ^~~~~ ^

I tried many ways, like convert type_ to be a const value, like this:

  1. const DataType dataType = type_;
  2. uint32_t size = TypeTrait&lt;dataType&gt;::size;

Then this problem arosed.

  1. main.cc: In member function void Test::Convert()’:
  2. main.cc:63:39: error: the value of type is not usable in a constant expression
  3. 63 | uint32_t size = TypeTrait&lt;type&gt;::size;
  4. | ^
  5. main.cc:62:24: note: type was not initialized with a constant expression
  6. 62 | const DataType type = GetType();
  7. | ^~~~
  8. main.cc:63:39: note: in template argument for type DataType
  9. 63 | uint32_t size = TypeTrait&lt;type&gt;::size;
  10. |

I know the program will be no problem if I pass enum element like this.

  1. uint32_t size = TypeTrait&lt;DataType::DATA_TYPE_UINT32&gt;::size;

I have no idea to solve this issue. So I must use switch case to handle this, which is against my wishes.
I just want to remove the switch case in my codes.
The code to be refactored:

  1. switch (dataType_) {
  2. case DATA_TYPE_INT8:
  3. byteSize = elemCnt * sizeof(int8_t);
  4. break;
  5. case DATA_TYPE_INT16:
  6. byteSize = elemCnt * sizeof(int16_t);
  7. break;
  8. case DATA_TYPE_FP16:
  9. byteSize = elemCnt * sizeof(uint16_t);
  10. break;
  11. case DATA_TYPE_UINT8:
  12. byteSize = elemCnt * sizeof(uint8_t);
  13. break;
  14. case DATA_TYPE_UINT16:
  15. byteSize = elemCnt * sizeof(uint16_t);
  16. break;
  17. case DATA_TYPE_INT32:
  18. byteSize = elemCnt * sizeof(int32_t);
  19. break;
  20. case DATA_TYPE_UINT32:
  21. byteSize = elemCnt * sizeof(uint32_t);
  22. break;
  23. case DATA_TYPE_FP32:
  24. byteSize = elemCnt * sizeof(float);
  25. break;
  26. }

答案1

得分: 1

以下是代码的中文翻译部分:

这是在运行时获取 TypeTrait&lt;type&gt;::size 的一种方法,而无需使用开关语句(需要 C++17):

  1. uint32_t datatypeSize(DataType type) {
  2. return [&amp;]&lt;std::size_t... Is&gt;(std::index_sequence&lt;Is...&gt;) {
  3. return ((static_cast&lt;std::size_t&gt;(type) == Is ? TypeTrait&lt;static_cast&lt;DataType&gt;(Is)&gt;::size : 0) + ...);
  4. }(std::make_index_sequence&lt;DATA_TYPE_UNKOWN&gt;{});
  5. }

演示

另一种方法,使用 std::array(来自 Jarod42 的评论 - 也需要 C++17):

  1. uint32_t datatypeSize(DataType type) {
  2. return [&amp;]&lt;std::size_t... Is&gt;(std::index_sequence&lt;Is...&gt;) {
  3. return std::array{TypeTrait&lt;static_cast&lt;DataType&gt;(Is)&gt;::size...}[type];
  4. }(std::make_index_sequence&lt;DATA_TYPE_UNKOWN&gt;{});
  5. }
英文:

Here is one way to fetch the TypeTrait&lt;type&gt;::size at runtime without a switch (C++17 required):

  1. uint32_t datatypeSize(DataType type) {
  2. return [&amp;]&lt;std::size_t... Is&gt;(std::index_sequence&lt;Is...&gt;) {
  3. return ((static_cast&lt;std::size_t&gt;(type) == Is ? TypeTrait&lt;static_cast&lt;DataType&gt;(Is)&gt;::size : 0) + ...);
  4. }(std::make_index_sequence&lt;DATA_TYPE_UNKOWN&gt;{});
  5. }

Demo

Another, using std::array (from Jarod42's comment - C++17 as well):

  1. uint32_t datatypeSize(DataType type) {
  2. return [&amp;]&lt;std::size_t... Is&gt;(std::index_sequence&lt;Is...&gt;) {
  3. return std::array{TypeTrait&lt;static_cast&lt;DataType&gt;(Is)&gt;::size...}[type];
  4. }(std::make_index_sequence&lt;DATA_TYPE_UNKOWN&gt;{});
  5. }

huangapple
  • 本文由 发表于 2023年7月13日 17:30:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76677883.html
匿名

发表评论

匿名网友

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

确定