如何将模板类型转换为字符串(如果它也可以是字符串)

How to convert a template type to string if it can be a string too?

本文关键字:字符串 如果 也可以 类型转换      更新时间:2023-10-16

我有类:

template <typename val_t>
class tracer_t : public base_tracer_t<val_t> {
    std::vector<std::string> m_trace;
public:
    virtual void push_fact(val_t fact) override {
        std::string str = "+ fact: " + to_string(fact);
        m_trace.push_back(std::move(str));
    }
    virtual void push_rule(const std::string &id, val_t val, bool tg) override {
        std::string str = "+ ";
        if (tg) { str += "target: "; }
        else { str += "rule: "; }
        str += id + " -> " + to_string(val);
        m_trace.push_back(std::move(str));
    }
    virtual void print() override {
        std::cout << "Stack trace: " << std::endl;
        for (auto it = m_trace.begin(); it != m_trace.end(); ++it) {
            std::cout << (*it) << std::endl;
        }
    }
private:
    std::string to_string(val_t val) {
        if (std::is_same<val_t, std::string>::value) {
            return (std::string)val;
        }
        return std::to_string(val);
    }
};

问题是,如果val_t std::string,它不会编译,因为:

tracer.hpp:49: error: no matching function for call to ‘to_string(std::__cxx11::basic_string<char>&)’
         return std::to_string(val);
                ~~~~~~~~~~~~~~^~~~~

但是我不知道如何解决它。我尝试手动检查类型,但错误在编译时,所以它没有帮助

如果您不想将整个类专用化std::string则可以使用 std::enable_ifif constexpr (c++17)

auto to_string(val_t val)
    -> typename std::enable_if<std::is_same<val_t, std::string>::value, std::string>::type 
{
    return static_cast<std::string>(val);
}
auto to_string(val_t val)
    -> typename std::enable_if<!std::is_same<val_t, std::string>::value, std::string>::type 
{
    return std::to_string(val);
}

或者更现代的方法,if constexpr

auto to_string(val_t val)
{
    if constexpr (std::is_same<val_t, std::string>::value)
    {
        return static_cast<std::string>(val);
    }
    else
    {
        return std::to_string(val);
    }
}

你可以为to_string提供一个新的重载

std::string to_string(const std::string& s) { return s; }

您可以将上面的代码放在类中,作为私有方法或合适的命名空间中,以避免在有人使用您的代码并希望编写自己的重载to_string时可能发生的冲突。

编辑:如下面的评论中所述,您不能在std命名空间中放置这样的重载,因为禁止新的std::to_string声明,请参阅扩展命名空间 std。

编辑:如果您需要调用std::to_string,您可能需要在代码中添加一个额外的to_string模板函数作为

template <typename T>
typename std::enable_if<!std::is_convertible<T, std::string>::value, std::string>::type to_string(T r) const { return std::to_string(r); }

(不要忘记#include <type_traits>)。

这是因为,即使您导入标准库std::to_string using namespace std,成员函数to_string也将具有优先级。请参阅讨论:C++:为什么成员函数优先于全局函数。在这里,您可以看到一个最小示例。

相关文章: