【问题标题】:Why does g++ not warn/err while concatenating an integer to a string using +=为什么 g++ 在使用 += 将整数连接到字符串时不会发出警告/错误
【发布时间】:2013-12-21 06:34:51
【问题描述】:

我有这个代码:

#include <iostream>                     
using namespace std; 

int main()                  
{                                                                                    
       string name = "John ";                     
       int age = 32;         
       name += age;    
       cout << name << endl;
       return 0;                                          
}

代码编译成功,但在运行时背叛,因为它默默地忽略了连接部分并打印:

John

我知道我们需要使用 stringstream 来完成任务。但是为什么上面的代码会编译呢? 因为下面的代码:

#include <iostream>
using namespace std;                                                                 

int main()                       
{                                                                                    
       string name = "John ";                              
       int age = 55;                                    
       name = name + age;             
       cout << name << endl;      
       return 0;
} 

适当地抛出错误:

错误:“姓名+年龄”中的“操作员+”不匹配

我从 Java 知道 a += ba = a + b 不同,因为前者将结果类型转换为 a 的类型。 Reference。但我认为这在 C++ 中并不重要,因为我们总是可以这样做:

   int a = 1;                                                                       
   float f = 3.33;                                                                  
   a = a + f;

无需担心与 Java 不同的精度警告可能丢失。需要在 C++ 中对此进行引用。

所以现在如果我们假设 name += age; 扩展为 name = string (name + age); 那么代码也不应该仅仅因为名称 + 年龄不合法而编译。

【问题讨论】:

  • 你确定它忽略了串联吗?我得到John 7,这是我所期望的,因为 55 是'7' 的 ASCII 值。
  • 另外,你的假设是错误的。对于类类型,a += b 不等于 a = a+b。第一个使用operator+=,第二个使用operator+operator=,这完全取决于类编写者如何实现这些运算符。
  • 是的。但我知道字符串的 += 就像 a + b 一样工作。是的,它打印 John 7。我的机器上的 age = 32。错字。现在一切都清楚了。谢谢!
  • 不损失精度?如果 a 是 int,那将如何发生?似乎 .33 不会使其 to 成为第一个运算符。你写的是‘a.operator=(a.+(f.operator int()))‘
  • 我的意思是警告。更新它。感谢您指出。

标签: java c++ g++ type-conversion implicit-conversion


【解决方案1】:

您需要使用-Wconversion 标志(我不清楚为什么它不包含在 -Wall 中)另请参阅Options to Request or Suppress Warnings 了解更多详细信息。当我添加该标志时,我在使用 gcc 时看到以下警告:

 warning: conversion to 'char' from 'int' may alter its value [-Wconversion]
    name += age;  
         ^

我们可以看到operator +=确实支持char,因此转换后的值确实被添加到name的末尾,它根本没有忽略操作。在 C++ 中,operator + for std::string 是与 operator += 不同的运算符。

在这种特定情况下:

name += age;

会翻译成这样的:

name.operator+=(static_cast<char>(age)) ;

如果我们有一个使用 operator + 的表达式而没有像这样的错误:

name = name + static_cast<char>( age );

将转化为:

operator+( name, static_cast<char>( age ) ) ;

answer 很好地介绍了您示例中 operator + 失败的原因,基本上 模板函数 不会执行转换,因此需要精确与 const/volatile 限定符的可能例外匹配。

Wconversion 更新

gcc 有一个带有 FAQWconversion Wiki,它有点过时,但它确实回答了为什么 -Wall 标志不包含此检查:

隐式转换在 C 语言中非常常见。这与前端没有数据流的事实相关(请参阅下一个问题),导致难以避免完美工作和有效代码的警告。 Wconversion 专为程序员愿意接受和解决无效警告的小众用途(安全审计、将 32 位代码移植到 64 位等)而设计。因此,如果没有明确请求,则不应启用它。

【讨论】:

  • 并且是 a += b;扩展为 a = (a 的类型) a + b;在 C++ 中就像在 Java 中一样?
  • @KodingKid 假设 a 是一个 std::string 这将转换为 a.operator+=(b),并在需要时为 b 进行适当的类型转换。
  • @KodingKid 否。在处理重载运算符时,就语言而言,+=+ 完全不相关。 (当然,任何优秀的程序员都会同时提供两者,如果他提供了一个,并且具有预期的语义关系。)
  • @KodingKid 另外,我认为 Java 也不是这样定义的。如果我写someComplicatedExpressionWithSideEffects += 'x'someComplicatedExpressionWithSideEffects 将不会被评估两次。
  • 来自 Java 文档,[docs.oracle.com/javase/specs/jls/se7/html/…“形式为 E1 op= E2 的复合赋值表达式等价于 E1 = (T) ((E1) op (E2)),其中 T 是E1 的类型,除了 E1 只计算一次。"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-12
  • 1970-01-01
  • 2012-09-29
  • 2014-06-11
  • 2016-08-24
  • 1970-01-01
相关资源
最近更新 更多