为什么这样做:
struct A {};
struct B {
B(A){}
};
void operator+(const B&, const B&) {}
int main()
{
A a1, a2;
a1 + a2;
}
这不是吗?
struct B {
B(const char*){}
};
void operator+(const B&, const B&) {} //error: invalid operands of types 'const char [6]' and 'const char [6]' to binary 'operator+'|
int main()
{
"Hello" + "world";
}
基本上,在第一个示例中a1
和a2
都通过隐式转换转换为B
个对象,并使用operator+(const B&, const B&)
添加。
从这个示例开始,我希望"Hello"
和"world"
再次通过隐式构造函数转换为B
个对象,并使用operator+(const B&, const B&)
添加到每个其他。相反,有一个错误,表明C风格的字符串不会尝试用户定义转换为B
以便添加。为什么是这样?是否存在阻止这种情况的基本属性?
答案 0 :(得分:5)
在您的第一个示例中,允许重载解析找到您的operator+
:
[C++14: 13.3.1.2/2]:
如果任一操作数的类型是类或枚举,则可以声明实现此运算符的用户定义的运算符函数,或者用户定义的转换可以是将操作数转换为适合内置运算符的类型所必需的。 在这种情况下,重载决策用于确定调用哪个运算符函数或内置运算符来实现运算符。 [..]
[C++14: 13.3.2/1]:
从为给定上下文(13.3.1)构造的候选函数集中,选择一组可行函数,通过比较从中选择最佳函数最佳拟合的参数转换序列(13.3.3)。可行函数的选择考虑了参数和函数参数之间的关系,而不是转换序列的排名。
[C++14: 13.3.2/2]:
首先,是一个可行的函数,候选函数应该有足够的参数来与列表中的参数一致。
- 如果列表中有
m
个参数,则所有具有m
个参数的候选函数都是可行的。- [..]
[C++14: 13.3.2/3]
:其次,要使F
成为可行的函数,每个参数都应存在隐式转换序列(13.3.3.1)F
的相应参数的参数。 [..]
(您可以自己检查“隐式转换序列”的措辞,看看operator+
调用是否允许;规则过于冗长,无法在此逐字复制。)
但是,在第二个示例中,重载决策受限于基本算术添加机制(未针对const char[N]
或const char*
定义的机制),有效地禁止任何operator+
函数被考虑:
[C++14: 13.3.1.2/1]:
如果表达式中的运算符的操作数没有类或枚举类型,则假定运算符是内置运算符并根据第5章进行解释。 /强>
[C++14: 5.7/1]:
[..] 另外,两个操作数都应具有算术或非范围枚举类型,或者一个操作数应该是一个完全指针 - 定义的对象类型,另一个应具有整数或无范围的枚举类型。 [..]
[C++14: 5.7/3]:
二元+运算符的结果是操作数的总和。
答案 1 :(得分:2)
<强> 1。解释编译器错误:
你不能使用'+'运算符连接两个字符串文字的原因,
是因为字符串文字只是字符数组,你不能连接两个数组。
数组将被隐式转换为第一个元素的指针。
或者正如标准所描述的那样:
<强> [conv.array] 强>
“N T数组”或“未知数组的数组”的左值或右值 T“可以转换为”指向T“的prvalue类型。结果 是指向数组第一个元素的指针。
你在上面的例子中真正做了什么,
试图将两个const char指针加在一起,这是不可能的。
<强> 2。为什么不隐式转换字符串文字:
由于数组和指针是基本类型,因此您无法像在类示例中那样提供隐式对话运算符。
要记住的主要事项是,std::string
知道如何接纳char[]
,但char[]
不知道如何成为std::string
。在您的示例中,您使用了B
作为char[]
的替代,但您还将其自身转换为A
。
第3。备选方案:强>
您可以通过省略plus运算符来连接字符串文字。
"stack" "overflow"; //this will work as you indented
或者,您可以将“堆栈”设为std :: string,然后使用std :: string的重载'+'运算符:
std::string("stack") + "overflow"; //this will work