【问题标题】:Automatically Concatenate Strings and Int C++自动连接字符串和 Int C++
【发布时间】:2015-03-23 10:44:26
【问题描述】:

在 Lua 中(抱歉,我最喜欢使用它),int 和 string 之间的转换是自动完成的,所以

"hi"..2

结果是

"hi2"

在 C++ 中(因为我似乎无法让默认的 C++11 stoi()to_string() 工作)我为自己定义了这些:

int stoi(string str) {
  char* ptr;
  strtol(str.c_str(), &ptr, 10);
}

string to_string(int i) {
  char* buf;
  sprintf(buf, "%d", i);
  return buf;
}

这基本上是默认值的定义方式。

然后我这样做了:

string operator+ (string& stuff, int why) {
  stuff.append(to_string(why));
}

我在下面的代码上试过:

void print(string str) {
  cout << str << endl;
}

int main() {
  cout << stoi("1") + 2 << endl;
  print("die" + 1);
  return 0;
}

然后输出

3
ie

为什么会这样,我该如何解决?

编辑: 现在的代码如下所示:

using namespace std;    

string to_string(int i) {
  char* buf;
  sprintf(buf, "%d", i);
  return buf;
}

string operator+ (string stuff, int why) {
  stuff.append(to_string(why));
  return stuff;
}

int main() {
  cout << string("die") + 2 << endl;
  return 0;
}

它只是不断给我堆栈转储。

【问题讨论】:

  • 你觉得char* buf; sprintf(buf, "%d", i); 有什么作用? buf 只是指向任何地方,但肯定不是指向要写入的有效区域。
  • erm,很明显的问题,你的意思是你不能让std::to_string() 工作?这对我来说似乎很好用??
  • 它告诉我to_string() 尚未声明。
  • 它应该在 C++11 中,即使我在编译期间使用 -std=c++14#include &lt;string&gt; 我仍然无法让它工作

标签: c++ c++11 concatenation


【解决方案1】:

print("die" + 1); 替换为cout &lt;&lt; std::string("die") + 1;

print() 不知道如何处理字符串。使用std::cout。 “die”是char*+1 将增加指针。

【讨论】:

  • cout &lt;&lt; "die" &lt;&lt; 1; :)
  • 好点@fjardon。我错过了那个明显的答案。我试图保留 ̀+` 运算符的使用。
  • 我知道你可以做到,只是我想看看我是否可以在 C++ 中实现 Lua 的一些便利
【解决方案2】:
std::string to_string(int i) {
  char buf[(sizeof(int)*CHAR_BIT+2)/3+3];
  sprintf(buf, "%d", i);
  return buf;
}

您需要创建一个实际的缓冲区来打印。数学是对最大小数 int 以字符为单位的快速高估; 3 位可以容纳 1 个十进制字符,加上 null,加上否定,加上舍入,加上 1 表示良好的度量。希望我没有犯错:做一些测试。

同时使用snprintf 而不是sprintf:缓冲区溢出是不可取的。

下一个问题是"hello"不是std::string,而是char const[6]——一个6个char的数组。它可以转换为 tomstd::string,但 +1 会将其转换为指向第一个字符的指针,然后将 +1 转换为第二个字符。

之前将其投射到std::string

最后,在std::string + int 上加载运算符的标准(实际上)是模棱两可的。这绝对是不好的做法,因为您不能合法地在 std 中执行此操作,并且您应该在类型的名称空间中重载运算符(因此 ADL 有效):这两个冲突。最重要的是,如果std 将来添加这样的+,您的代码就会开始出现奇怪的行为。最重要的是,操作符是类接口的一部分,修改你不“拥有”的类的接口是粗鲁和坏习惯。

编写自己的字符串类,它拥有std::string。或字符串视图。

最后,考虑告诉你的编译器使用 c++11,你可能只需要传递一个标志给它,比如-std=c++11

【讨论】:

    【解决方案3】:
    std::string s1("h1");
    std::string s2("2");
    s1 += s2;
    

    如果您使用的是 C++11 兼容的编译器,您可以像这样将 int 转换为字符串:

    int i = 2;
    std::string s = std::to_string(i);
    

    如果您使用的是 Boost 库:

    #include <boost/lexical_cast.hpp>
    
    int i = 2;
    std::string s = boost::lexical_cast<std::string>(i);
    

    请不要在 C++ 中将原始字符指针用于字符串。

    【讨论】:

      【解决方案4】:

      在你自己的类型之外重载 operator+ 充其量是危险的。

      只需将std::to_stringoperator++= 结合使用,例如

      std::string x = "hi";
      x += std::to_string(2);
      

      【讨论】:

        【解决方案5】:

        C++14 引入了一个用户定义的文字,它接受一个字符串文字(应用转换以使其成为一个指针)并返回一个std::string。在 C++11 中,您可以自己编写(取自 libstdc++):

        inline std::string
        operator""_s(const char* str, size_t len)
        { 
          return std::string{str, len}; 
        }
        

        (注意:前面没有下划线的 UDL 是保留名称)

        你可以这样使用它:

        // Assumes operator+ is overloaded
        print("die"_s + 1);
        

        Demo

        【讨论】:

        • __str__len 在技术上也是保留的。
        【解决方案6】:

        "die" 不是std::string。这是string literal

        因此,当您将 1 添加到字符串文字时,它会衰减为 const char*,而 + 1 只是将该指针递增 - 到下一个字符 'i'

        然后您使用递增的指针调用print,这会导致使用该指针构造std::string。由于它指向'i' 字符,所以构造的字符串被初始化为"ie"

        您必须首先从您的字符串文字中创建一个std::string 以使其调用您的operator+

        std::cout << std::string("die") + 1;
        

        然后对您的operator+ 进行一些修复:

        string operator+ (string stuff, int why) {
          return stuff.append(to_string(why));
        }
        

        现在可以了。

        【讨论】:

        • "die" 不是const char*。它是一个衰减为指针的 const char 数组。二进制 + 运算符也不增加任何内容(该术语意味着其中一个操作数已被修改)。您也不能重载不接受至少一个类类型参数的运算符。
        • 是的,它给我一个错误,说它必须有一个类或枚举类型的参数
        • 为什么我被否决了?您应该说出问题所在,而不是默默地反对。如果你没有什么要说的,你也可以不投票,不会伤害任何人。
        • 改进建议:template&lt;class Rhs,class=typename enable_if&lt;is_convertible&lt;decltype(to_string(declval&lt;Rhs&gt;())), string&gt;::value&gt;::type&gt; string operator+(string lhs, Rhs&amp;&amp;rhs){return lhs.append(to_string(std::forward&lt;Rhs&gt;(rhs)));} 现在可以添加任何带有std::string to_string 重载的内容。 (或者为can_to_string 写一个单独的特征并使用它,或者使用标签调度,等等)
        猜你喜欢
        • 1970-01-01
        • 2013-09-14
        • 2011-07-07
        • 2017-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-24
        • 1970-01-01
        相关资源
        最近更新 更多