【问题标题】:How to convert a template type to string if it can be a string too?如果模板类型也可以是字符串,如何将其转换为字符串?
【发布时间】:2019-06-14 15:59:10
【问题描述】:

我有课:

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_tstd::string 则无法编译,因为:

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

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

【问题讨论】:

标签: c++ string c++11 templates


【解决方案1】:

如果你不想为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);
    }
}

【讨论】:

  • 您始终可以只专注于这一功能。 :)
  • 很快,C++ 将采用 Perl 的口号——TIMTIWTDI。
  • 为什么是static_cast?事实上,我希望编译器会警告不必要的强制转换。
  • @KonradRudolph 你说得对,我只是拿了操作的代码并对其进行了修改,而不考虑演员表是不必要的。
  • 对不起,这是我的错,我忘了指定c++11 标签。我使用的是 11 标准
【解决方案2】:

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

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

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

编辑:正如下面的 cmets 所述,您不能在 std 命名空间中放置这样的重载,因为 std::to_string 的新声明是被禁止的,请参阅 Extending the namespace 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 &lt;type_traits&gt;)。

这是因为,即使你通过using namespace std 导入标准库std::to_string,成员函数to_string 也会有优先权。请参阅讨论:C++: Why member function has priority over global functionHere 你可以看到一个最小的例子。

【讨论】:

  • 禁止重载std::to_string!充其量你可以在命名空间std 中专门化模板函数,但即使这样在 C++20 中也会消失。
  • @jrok 没关系,但不是std::to_string 你超载了。
  • @MaxLanghof 和这里一样,不是吗?
  • @MaxLanghof 答案显然犯了一个错误,旨在引用std之外的to_string函数。
  • @Шах 不是真的。它说您可以在 c++20 中添加 类模板 的特化。 std::to_string 既不是类,也不是模板函数。这就是为什么你必须在类中添加上面的代码,或者在一个合适的命名空间中,而不是std
猜你喜欢
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
相关资源
最近更新 更多