在模板参数中将枚举转换为 int
Casting enum to int in a template parameter
为了方便特定的 class,我已经定义了一个自定义 enum
,现在它妨碍了更通用的进程对其进行处理。
我应该如何执行此类型转换?
// A templated value holder:
template <typename T>
struct Holder {
T _value;
};
// A more general process..
template <typename T>
struct General {
Holder<T> *holder;
};
// ..over integral types:
struct IntGeneral : General<int> {};
// Here is something interesting: I can tell that this process will work on
// any enum type. But I've found no way to make this explicit.
// Convenience for a particular case
typedef enum {One, Two, Three} Enum;
typedef Holder<Enum> Particular;
int main() {
Particular* a( new Particular { One } );
IntGeneral ig { static_cast<Holder<int>*>(a) }; // compiler grumbles
return EXIT_SUCCESS;
}
这是我得到的:
error: invalid static_cast from type ‘Particular* {aka Holder<Enum>*}’ to type ‘Holder<int>*’
有什么方法可以保持方便 Enum
并编译此代码?
编辑:原来是 XY problem。此处接受了对 Y 的回答,并讨论了几个。
X 已移至 .
我认为使它工作的最简单方法是专门化 Holder<Enum>
以便它隐式转换为 Holder<Int>
.
template<>
struct Holder<Enum> {
Enum _value;
operator Holder<Int>() const { return { _value }; }
};
虽然这将制作枚举的副本,因此这可能不会完全按照您的要求执行,具体取决于 General
进程中发生的事情。
如果 T
可转换为 U
且 T
可转换为 Holder<T>
,则您可以添加一个模板转换函数,允许将 Holder<T>
转换为 Holder<U>
一个枚举:
template <typename T>
struct Holder {
T _value;
template <typename U,
typename = std::enable_if_t<
std::is_convertible<T, U>::value &&
std::is_enum<T>::value
>>
operator Holder<U>() const {
return {_value};
}
};
可能 只需 可转换性检查就足够了,具体取决于您的用例。
这会让你写:
Holder<int> i = Holder<Enum>{One};
但它不会让您将指针转换为强制转换。您必须分配一个全新的 Holder<int>*
来存储 Holder<Enum>*
。
问题是 static_cast
不适用于转换不同类型的指针。我建议您使用 reinterpret_cast
,它应该可以完成工作。此外,您不能使用指针实例化 IntGeneral
类型的对象。
是否足以替换:
IntGeneral ig { static_cast<Holder<int>*>(a) }; // compiler grumbles
有:
IntGeneral ig { new Holder<int>{a->_value} };
因为是结构体,所以可以访问值。就我个人而言,我会使用 getter 和 setter,但正如所展示的那样,这应该可以满足您的需求。
交替
您可以替换:
typedef Holder<Enum> Particular;
有:
typedef Holder<int> Particular;
因为 int
可以容纳 Enum
您可以进行一些更改:
- 向 'Holder' 添加可以引用通用类型和特定类型的父类型。
- 为接收 T 的 Holder 定义一个构造函数
- 为接收 Holder 地址类型的 General 定义一个构造函数
对于 IntGeneral 的初始化列表(这是一个奇怪的名字,因为它不是通用的,但我明白了)用 "Holder*" 地址启动。
struct HolderBase {};
template <typename T>
struct Holder : HolderBase{
Holder(T value){ _value = value; }
T _value;
};
template <typename T>
struct General {
General(Holder<T>* h){ holder = h; }
Holder<T>* holder;
};
struct IntGeneral : General<int> {
IntGeneral(Holder<int>* holder) : General<int>(holder){}
};
typedef enum { One, Two, Three } Enum;
typedef Holder<Enum> Particular;
int main() {
HolderBase* a(new Particular{ One });
IntGeneral ig{ static_cast<Holder<int>*>(a) };
return 0;
}
希望这就是您要找的东西
为了方便特定的 class,我已经定义了一个自定义 enum
,现在它妨碍了更通用的进程对其进行处理。
我应该如何执行此类型转换?
// A templated value holder:
template <typename T>
struct Holder {
T _value;
};
// A more general process..
template <typename T>
struct General {
Holder<T> *holder;
};
// ..over integral types:
struct IntGeneral : General<int> {};
// Here is something interesting: I can tell that this process will work on
// any enum type. But I've found no way to make this explicit.
// Convenience for a particular case
typedef enum {One, Two, Three} Enum;
typedef Holder<Enum> Particular;
int main() {
Particular* a( new Particular { One } );
IntGeneral ig { static_cast<Holder<int>*>(a) }; // compiler grumbles
return EXIT_SUCCESS;
}
这是我得到的:
error: invalid static_cast from type ‘Particular* {aka Holder<Enum>*}’ to type ‘Holder<int>*’
有什么方法可以保持方便 Enum
并编译此代码?
编辑:原来是 XY problem。此处接受了对 Y 的回答,并讨论了几个。
X 已移至
我认为使它工作的最简单方法是专门化 Holder<Enum>
以便它隐式转换为 Holder<Int>
.
template<>
struct Holder<Enum> {
Enum _value;
operator Holder<Int>() const { return { _value }; }
};
虽然这将制作枚举的副本,因此这可能不会完全按照您的要求执行,具体取决于 General
进程中发生的事情。
如果 T
可转换为 U
且 T
可转换为 Holder<T>
,则您可以添加一个模板转换函数,允许将 Holder<T>
转换为 Holder<U>
一个枚举:
template <typename T>
struct Holder {
T _value;
template <typename U,
typename = std::enable_if_t<
std::is_convertible<T, U>::value &&
std::is_enum<T>::value
>>
operator Holder<U>() const {
return {_value};
}
};
可能 只需 可转换性检查就足够了,具体取决于您的用例。
这会让你写:
Holder<int> i = Holder<Enum>{One};
但它不会让您将指针转换为强制转换。您必须分配一个全新的 Holder<int>*
来存储 Holder<Enum>*
。
问题是 static_cast
不适用于转换不同类型的指针。我建议您使用 reinterpret_cast
,它应该可以完成工作。此外,您不能使用指针实例化 IntGeneral
类型的对象。
是否足以替换:
IntGeneral ig { static_cast<Holder<int>*>(a) }; // compiler grumbles
有:
IntGeneral ig { new Holder<int>{a->_value} };
因为是结构体,所以可以访问值。就我个人而言,我会使用 getter 和 setter,但正如所展示的那样,这应该可以满足您的需求。
交替
您可以替换:
typedef Holder<Enum> Particular;
有:
typedef Holder<int> Particular;
因为 int
可以容纳 Enum
您可以进行一些更改:
- 向 'Holder' 添加可以引用通用类型和特定类型的父类型。
- 为接收 T 的 Holder 定义一个构造函数
- 为接收 Holder 地址类型的 General 定义一个构造函数
对于 IntGeneral 的初始化列表(这是一个奇怪的名字,因为它不是通用的,但我明白了)用 "Holder*" 地址启动。
struct HolderBase {}; template <typename T> struct Holder : HolderBase{ Holder(T value){ _value = value; } T _value; }; template <typename T> struct General { General(Holder<T>* h){ holder = h; } Holder<T>* holder; }; struct IntGeneral : General<int> { IntGeneral(Holder<int>* holder) : General<int>(holder){} }; typedef enum { One, Two, Three } Enum; typedef Holder<Enum> Particular; int main() { HolderBase* a(new Particular{ One }); IntGeneral ig{ static_cast<Holder<int>*>(a) }; return 0; }
希望这就是您要找的东西