【问题标题】:How to compile programm with error "no matching function for call to 'to_string'"? c++如何编译出现错误“没有匹配函数调用'to_string'”的程序? C++
【发布时间】:2021-08-05 19:37:19
【问题描述】:

如果我在这里有 DATA_T = std::string,我无法编译这段代码,因为错误“没有匹配函数调用 'to_string'”。该函数不允许将字符串转换为字符串。但是无论如何我都需要获取字符串,我该如何解决这个错误并编译程序?

template <typename DATA_T>
std::string get_string(DATA_T subdata) {
  std::string data = "...";
  if (typeid(subdata) == typeid(std::string))
    data += subdata;
  else
    data += std::to_string(subdata);
  return data;
}

【问题讨论】:

标签: c++


【解决方案1】:

在 C++17 中,使用 if constexpr 可以使其更简单:

#include <string>
#include <type_traits>

template <typename DATA_T>
std::string get_string(DATA_T subdata) {
  std::string data = "...";
  if constexpr (std::is_same_v<DATA_T, std::string>)
    data += subdata;
  else
    data += std::to_string(subdata);
  return data;
}

有关 C++17 之前的解决方案,请参阅 the other answer

【讨论】:

    【解决方案2】:

    您可以编写一个重载,当参数是 std::string 时,您可以编写一个优先使用的重载,而不是尝试在函数体内对模板参数的类型进行分支。

    template <typename DATA_T>
    std::string get_string(DATA_T subdata) {
      std::string data = "...";
      data += std::to_string(subdata);
      return data;
    }
    
    std::string get_string(std::string subdata)
    {
      std::string data = "...";
      data += subdata;
      return data;
    }
    

    【讨论】:

    • 不要专门化,而是重载。如果您删除 template &lt;&gt;,代码仍然可以编译。专业化可能会导致一些难以发现的“错误”
    • 好建议。重载也意味着隐式转换为std::string 的类型将能够使用替代版本。编辑。
    • 那些实际上仍然会被模板拾取,因为它是更好的匹配。
    • 哦,对了。我想你可以 SFINAE 模板版本只选择算术类型或其他东西,具体取决于 DATA_T 的有效类型实际上是什么。
    【解决方案3】:

    如其他答案所示,您可以为std::string 添加特殊情况。这将解决您对std::string 的问题,但是其他类型呢?

    当我第一次看到to_string 时,我相当失望,因为它只有一组有限的重载。但是,我误解了 to_string 的含义。它旨在完全转换为字符串,就像std::sprintf 使用正确的格式说明符一样。由于sprintf 继承自C,它不能将所有类型转换为可以在C++ 中转换为字符串的字符串。无法直接通过sprintf 启用自定义类型的转换。正因为如此,to_string 也有同样的限制。特别是没有to_string(const std::string&amp;)

    重载std::ostream&amp; operator&lt;&lt;(std::ostream&amp;,const T&amp;) 更加灵活。你想用foobar 打电话给get_string?为什么不:

    #include <iostream>
    #include <sstream>
    
    template <typename DATA_T>
    std::string get_string(DATA_T subdata) {
        std::stringstream data;
        data << "...";
        data << subdata;
        return data.str();
    }
    
    struct foo {};
    
    std::ostream& operator<<(std::ostream& out,const foo& f){
        return out << "foo";
    }
    
    int main() {
        foo f;
        std::cout << get_string(f);
    }
    

    如果您确实想像 sprintf 那样进行转换,我可能会继续使用其他答案中提供的解决方案之一。

    【讨论】:

    • 我认为你对std::to_string 感到失望是对的(我做了最初的设计)。模仿sprintf 不是设计目标;这是规范的便利。设计目标是提供一组简单的转换,标准数字类型是一个明显的集合。事后看来,没有其他类型是想象力的失败。更不用说对复杂性的恐惧了。
    • @PeteBecker 那么我很高兴我没有像以前的答案那样表达我的失望;)。事后看来,批评总是很容易的。仍然有 ADL 作为定制点。尽管我尽量避免 ADL,因为我认为它太晦涩难懂(考虑到我还必须说服同事)。正如这个答案可能暗示的那样,重载operator&lt;&lt; 也并非没有陷阱。将来可以扩展to_string 吗?我记得有一个提案建议基于&lt;&lt; 提出一些to_string 但iirc 它与当前的to_string 不兼容。
    • 我不再参与标准化,所以我不知道未来可能会发生什么。
    猜你喜欢
    • 2015-06-02
    • 2013-11-21
    • 2016-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多