扩展 std::to_string 以支持枚举和指针
Extending std::to_string to support enums and pointers
我有以下模板函数ToString
,它将std::to_string
用于算术类型,并尝试对指针和枚举类型进行static_cast
。
#include <iostream>
#include <string>
template <typename T>
std::string ToString(T val)
{
if (std::is_arithmetic<T>::value)
{
return std::to_string(val);
}
if (std::is_enum<T>::value || std::is_pointer<T>::value)
{
return std::to_string(static_cast<size_t>(val));
}
}
enum class MyEnum : int
{
E1,
E2
};
int main(int argc, char* argv[])
{
MyEnum e = MyEnum::E1;
const void* ptr = &e;
std::cout << ToString(e) << std::endl;
std::cout << ToString(ptr) << std::endl;
}
上面的代码无法编译。有没有办法实现所需的功能?
VS2017上的编译错误是
Error C2440 'static_cast': cannot convert from 'T' to 'size_t'
Error C2665 'std::to_string': none of the 9 overloads could convert all the argument types
你需要使用 if constexpr
.否则,使用指针或枚举实例化std::to_string
,这将无法编译 (C2665(。
此外,您不能静态强制转换指向整数 (C2440( 的指针。你需要重新诠释演员表。
此外,如果传递的参数既不是枚举、指针也不是算术类型,您的函数就会缺少返回。在这种情况下,行为是不确定的。解决方案:始终返回某些内容(如果模板参数无效,则编译失败(。
此外,不能保证size_t
足够大以表示所有指针值。 你想要std::uintptr_t
.
您可能希望使用std::underlying_type_t
来获取正确的enum class
类型。
if constexpr (std::is_pointer<T>::value) {
return std::to_string(reinterpret_cast<std::uintptr_t>(val));
} else if constexpr (std::is_enum<T>::value)
{
return std::to_string(static_cast<std::underlying_type_t<T>>(val));
} else {
return std::to_string(val);
}
添加缺少的标头后,这应该可以工作。
附言设计说明:现在打印指针,整数或枚举在输出中都是相同的。您可能希望添加一些前缀或类似前缀以消除结果的歧义。
我认为这里的直接问题是 T 是否为指针类型的static_cast
。要将指针转换为整数,您需要使用reinterpret_cast
而不是static_cast
,因为该强制转换从根本上将指针变量的位重新解释为数字,而不是简单地告诉C++如果认为指向的对象,则更改类型对象。
正如注释所指出的,您可能需要对代码进行一些重组才能使其正常工作,因为当您实例化模板时,函数主体中的所有代码都将使用该选择 T 进行编译。若要添加到有关如何执行此操作的建议列表中,如果您使用的是 C++17 编译器,请考虑在代码中使用 if constexpr
而不是常规if
。这将告诉C++只有条件地编译 if/else 链的不同分支。
适用于 c++11。 我把它黑在一起,所以我想我不妨发布它。 不过,您应该注意此处的其他答案。
#include <cstdint>
#include <string>
#include <type_traits>
#include <iostream>
template <typename T>
auto ToString(T val) -> typename std::enable_if<std::is_arithmetic<T>::value, std::string>::type
{
return std::to_string(val);
}
template <typename T>
auto ToString(T val) -> typename std::enable_if<std::is_enum<T>::value, std::string>::type
{
return std::to_string(static_cast<typename std::underlying_type<T>::type>(val));
}
template <typename T>
auto ToString(T val) -> typename std::enable_if<std::is_pointer<T>::value, std::string>::type
{
return std::to_string(reinterpret_cast<std::uintptr_t>(val));
}
enum class MyEnum : int
{
E1,
E2
};
int main(int argc, char* argv[])
{
MyEnum e = MyEnum::E1;
const void* ptr = &e;
std::cout << ToString(e) << std::endl;
std::cout << ToString(ptr) << std::endl;
}
- 不带大括号的枚举形式
- 枚举环境变量的惯用C++14/C++17方法
- 类似枚举的计算常量
- 如何正确实现和访问运算符的各种自定义枚举器
- 错误:从"int"到枚举c++的转换无效
- C++中构造函数中的枚举
- 访问在 C++ 结构中声明的枚举变量
- 枚举类'classname'的多重定义
- 强枚举类型定义:Clang Bug 还是 C++11 标准不确定性?
- typedef 枚举和枚举类有什么区别?
- 为什么我的开关/机箱在使用枚举时默认?
- 标准::可选枚举的比较运算符
- C++两个源文件之间共享的枚举的静态实例
- 打印没有铸件的枚举可以在C++中吗?
- 枚举成员与静态 int 成员?
- 如何获得支持枚举的类型
- 扩展 std::to_string 以支持枚举和指针
- 为什么作用域枚举默认支持运算符'<'?
- RCPP 枚举支持
- 编译器对枚举值的支持