扩展std :: to_string以支持枚举和指针

时间:2019-04-02 18:25:15

标签: c++

我具有以下模板函数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

3 个答案:

答案 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;                                                                                                                                                                     
}