英文:
How to pass a enum variable to a struct with template specialization for enum
问题
我设计了一个带有模板特化的结构体,用于枚举类型,如下所示:
template<DataType type>
struct TypeTrait;
template<>
struct TypeTrait<DATA_TYPE_INT8> {
static constexpr uint32_t size = sizeof(int8_t);
};
template<>
struct TypeTrait<DATA_TYPE_INT16> {
static constexpr uint32_t size = sizeof(int16_t);
};
template<>
struct TypeTrait<DATA_TYPE_FP16> {
static constexpr uint32_t size = sizeof(uint16_t);
};
template<>
struct TypeTrait<DATA_TYPE_UINT8> {
static constexpr uint32_t size = sizeof(uint8_t);
};
template<>
struct TypeTrait<DATA_TYPE_UINT16> {
static constexpr uint32_t size = sizeof(uint16_t);
};
template<>
struct TypeTrait<DATA_TYPE_INT32> {
static constexpr uint32_t size = sizeof(int32_t);
};
template<>
struct TypeTrait<DATA_TYPE_UINT32> {
static constexpr uint32_t size = sizeof(uint32_t);
};
template<>
struct TypeTrait<DATA_TYPE_FP32> {
static constexpr uint32_t size = sizeof(float);
};
枚举类型 DataType 定义如下:
enum DataType {
DATA_TYPE_INT8 = 0,
DATA_TYPE_INT16 = 1,
DATA_TYPE_FP16 = 2,
DATA_TYPE_UINT8 = 3,
DATA_TYPE_UINT16 = 4,
DATA_TYPE_INT32 = 5,
DATA_TYPE_UINT32 = 6,
DATA_TYPE_FP32 = 7,
DATA_TYPE_UNKNOWN
};
我想要将一个 DataType 变量传递给 TypeTrait 结构体,如下所示:
class Test {
public:
...
void Convert() {
...
uint32_t size = TypeTrait<type_>::size;
...
}
private:
DataType type_;
};
当我这样做时,在编译程序时出现了问题:
main.cc: In member function ‘void Test::Convert()’:
main.cc:63:35: error: use of ‘this’ in a constant expression
63 | uint32_t size = TypeTrait<type_>::size;
| ^~~~~
main.cc:63:40: error: use of ‘this’ in a constant expression
63 | uint32_t size = TypeTrait<type_>::size;
| ^
main.cc:63:35: note: in template argument for type ‘DataType’
63 | uint32_t size = TypeTrait<type_>::size;
| ^~~~~
我尝试了许多方法,例如将 type_
转换为常量值,如下所示:
const DataType dataType = type_;
uint32_t size = TypeTrait<dataType>::size;
然后出现了这个问题:
main.cc: In member function ‘void Test::Convert()’:
main.cc:63:39: error: the value of ‘type’ is not usable in a constant expression
63 | uint32_t size = TypeTrait<type>::size;
| ^
main.cc:62:24: note: ‘type’ was not initialized with a constant expression
62 | const DataType type = GetType();
| ^~~~
main.cc:63:39: note: in template argument for type ‘DataType’
63 | uint32_t size = TypeTrait<type>::size;
|
我知道如果我像这样传递枚举元素,程序就不会出问题:
uint32_t size = TypeTrait<DataType::DATA_TYPE_UINT32>::size;
我不知道如何解决这个问题。所以我必须使用 switch 语句来处理这个问题,这违背了我的愿望。我只是想在我的代码中删除 switch 语句。要重构的代码如下:
switch (dataType_) {
case DATA_TYPE_INT8:
byteSize = elemCnt * sizeof(int8_t);
break;
case DATA_TYPE_INT16:
byteSize = elemCnt * sizeof(int16_t);
break;
case DATA_TYPE_FP16:
byteSize = elemCnt * sizeof(uint16_t);
break;
case DATA_TYPE_UINT8:
byteSize = elemCnt * sizeof(uint8_t);
break;
case DATA_TYPE_UINT16:
byteSize = elemCnt * sizeof(uint16_t);
break;
case DATA_TYPE_INT32:
byteSize = elemCnt * sizeof(int32_t);
break;
case DATA_TYPE_UINT32:
byteSize = elemCnt * sizeof(uint32_t);
break;
case DATA_TYPE_FP32:
byteSize = elemCnt * sizeof(float);
break;
}
英文:
I design a struct with template specialization for enum, like this:
template<DataType type>
struct TypeTrait;
template<>
struct TypeTrait<DATA_TYPE_INT8> {
static constexpr uint32_t size = sizeof(int8_t);
};
template<>
struct TypeTrait<DATA_TYPE_INT16> {
static constexpr uint32_t size = sizeof(int16_t);
};
template<>
struct TypeTrait<DATA_TYPE_FP16> {
static constexpr uint32_t size = sizeof(uint16_t);
};
template<>
struct TypeTrait<DATA_TYPE_UINT8> {
static constexpr uint32_t size = sizeof(uint8_t);
};
template<>
struct TypeTrait<DATA_TYPE_UINT16> {
static constexpr uint32_t size = sizeof(uint16_t);
};
template<>
struct TypeTrait<DATA_TYPE_INT32> {
static constexpr uint32_t size = sizeof(int32_t);
};
template<>
struct TypeTrait<DATA_TYPE_UINT32> {
static constexpr uint32_t size = sizeof(uint32_t);
};
template<>
struct TypeTrait<DATA_TYPE_FP32> {
static constexpr uint32_t size = sizeof(float);
};
enum DataType is defined like this:
enum DataType {
DATA_TYPE_INT8 = 0,
DATA_TYPE_INT16 = 1,
DATA_TYPE_FP16 = 2,
DATA_TYPE_UINT8 = 3,
DATA_TYPE_UINT16 = 4,
DATA_TYPE_INT32 = 5,
DATA_TYPE_UINT32 = 6,
DATA_TYPE_FP32 = 7,
DATA_TYPE_UNKOWN
};
And I want pass a DataType variable to struct TypeTrait, like this:
class Test {
public:
...
void Convert() {
...
uint32_t size = TypeTrait<type_>::size;
...
}
private:
DataType type_;
};
When I do this, there is a problem while compiling my program:
main.cc: In member function ‘void Test::Convert()’:
main.cc:63:35: error: use of ‘this’ in a constant expression
63 | uint32_t size = TypeTrait<type_>::size;
| ^~~~~
main.cc:63:40: error: use of ‘this’ in a constant expression
63 | uint32_t size = TypeTrait<type_>::size;
| ^
main.cc:63:35: note: in template argument for type ‘DataType’
63 | uint32_t size = TypeTrait<type_>::size;
| ^~~~~ ^
I tried many ways, like convert type_
to be a const value, like this:
const DataType dataType = type_;
uint32_t size = TypeTrait<dataType>::size;
Then this problem arosed.
main.cc: In member function ‘void Test::Convert()’:
main.cc:63:39: error: the value of ‘type’ is not usable in a constant expression
63 | uint32_t size = TypeTrait<type>::size;
| ^
main.cc:62:24: note: ‘type’ was not initialized with a constant expression
62 | const DataType type = GetType();
| ^~~~
main.cc:63:39: note: in template argument for type ‘DataType’
63 | uint32_t size = TypeTrait<type>::size;
|
I know the program will be no problem if I pass enum element like this.
uint32_t size = TypeTrait<DataType::DATA_TYPE_UINT32>::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:
switch (dataType_) {
case DATA_TYPE_INT8:
byteSize = elemCnt * sizeof(int8_t);
break;
case DATA_TYPE_INT16:
byteSize = elemCnt * sizeof(int16_t);
break;
case DATA_TYPE_FP16:
byteSize = elemCnt * sizeof(uint16_t);
break;
case DATA_TYPE_UINT8:
byteSize = elemCnt * sizeof(uint8_t);
break;
case DATA_TYPE_UINT16:
byteSize = elemCnt * sizeof(uint16_t);
break;
case DATA_TYPE_INT32:
byteSize = elemCnt * sizeof(int32_t);
break;
case DATA_TYPE_UINT32:
byteSize = elemCnt * sizeof(uint32_t);
break;
case DATA_TYPE_FP32:
byteSize = elemCnt * sizeof(float);
break;
}
答案1
得分: 1
以下是代码的中文翻译部分:
这是在运行时获取 TypeTrait<type>::size
的一种方法,而无需使用开关语句(需要 C++17):
uint32_t datatypeSize(DataType type) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return ((static_cast<std::size_t>(type) == Is ? TypeTrait<static_cast<DataType>(Is)>::size : 0) + ...);
}(std::make_index_sequence<DATA_TYPE_UNKOWN>{});
}
另一种方法,使用 std::array
(来自 Jarod42 的评论 - 也需要 C++17):
uint32_t datatypeSize(DataType type) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::array{TypeTrait<static_cast<DataType>(Is)>::size...}[type];
}(std::make_index_sequence<DATA_TYPE_UNKOWN>{});
}
英文:
Here is one way to fetch the TypeTrait<type>::size
at runtime without a switch (C++17 required):
uint32_t datatypeSize(DataType type) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return ((static_cast<std::size_t>(type) == Is ? TypeTrait<static_cast<DataType>(Is)>::size : 0) + ...);
}(std::make_index_sequence<DATA_TYPE_UNKOWN>{});
}
Another, using std::array
(from Jarod42's comment - C++17 as well):
uint32_t datatypeSize(DataType type) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return std::array{TypeTrait<static_cast<DataType>(Is)>::size...}[type];
}(std::make_index_sequence<DATA_TYPE_UNKOWN>{});
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论