我具有以下模板函数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
答案 0 :(得分:4)
您需要使用toISOString()
。否则,您将使用无法编译的指针或枚举实例化if constexpr
(C2665)。
此外,您不能将指针静态转换为整数(C2440)。您需要重新解释演员表。
此外,如果传递的参数既不是枚举,指针也不是算术类型,则函数缺少返回值。在这种情况下,行为是不确定的。解决方案:始终返回某些内容(如果模板参数无效,则编译失败)。
此外,不能保证std::to_string
的大小足以表示所有指针值。您想要size_t
。
您可能想使用std::uintptr_t
来获取std::underlying_type_t
的正确类型。
enum class
一旦添加了缺少的标题,这应该可以工作。
P.S。设计说明:现在打印指针,整数或枚举的输出都相同。您可能需要添加一些前缀或类似内容以消除结果的歧义。
答案 1 :(得分:1)
我认为,如果T是指针类型,那么这里的紧迫问题是static_cast
。要将指针转换为整数,您需要使用reinterpret_cast
而不是static_cast
,因为该类型转换从根本上将指针变量的位重新解释为数字,而不是简单地告诉C ++更改哪种类型指向对象的想法。
正如评论所指出的那样,您可能需要对代码进行一些重组以使其正常工作,因为在实例化模板时,函数主体中的所有代码都将与之一起编译。要添加至有关如何执行此操作的建议列表,如果您使用的是C ++ 17编译器,请考虑在代码中使用if constexpr
而不是常规的if
。这将告诉C ++仅有条件地编译if / else链的不同分支。
答案 2 :(得分:1)
这适用于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;
}