Car*_*rra 3 c++ operator-overloading temporary visual-c++
为什么Visual C++编译器在这里调用错误的重载?
我有一个ostream的子类,我用它来定义格式化的缓冲区.有时我想创建一个临时的,并立即插入一个字符串,使用通常的<<运算符,如下所示:
M2Stream() << "the string";
Run Code Online (Sandbox Code Playgroud)
不幸的是,程序调用运算符<<(ostream,void*)成员重载,而不是运算符<<(ostream,const char*)非成员.
我将下面的示例编写为测试,我在其中定义了自己的M2Stream类来重现问题.
我认为问题是M2Stream()表达式产生一个临时的,这在某种程度上导致编译器更喜欢void*overload.但为什么?事实证明,如果我为非成员重载const M2Stream&做第一个参数,我就会产生歧义.
另一个奇怪的事情是,如果我首先定义一个const char*类型的变量然后调用它而不是文字字符串字符串,它会调用所需的const char*重载,如下所示:
const char *s = "char string variable";
M2Stream() << s;
Run Code Online (Sandbox Code Playgroud)
就好像文字字符串的类型不同于const char*变量!它们不应该是一样的吗?当我使用临时字符串和字符串字符串时,为什么编译器会调用void*重载?
#include "stdafx.h"
#include <iostream>
using namespace std;
class M2Stream
{
public:
M2Stream &operator<<(void *vp)
{
cout << "M2Stream bad operator<<(void *) called with " << (const char *) vp << endl;
return *this;
}
};
/* If I make first arg const M2Stream &os, I get
\tests\t_stream_insertion_op\t_stream_insertion_op.cpp(39) : error C2666: 'M2Stream::operator <<' : 2 overloads have similar conversions
\tests\t_stream_insertion_op\t_stream_insertion_op.cpp(13): could be 'M2Stream &M2Stream::operator <<(void *)'
\tests\t_stream_insertion_op\t_stream_insertion_op.cpp(20): or 'const M2Stream &operator <<(const M2Stream &,const char *)'
while trying to match the argument list '(M2Stream, const char [45])'
note: qualification adjustment (const/volatile) may be causing the ambiguity
*/
const M2Stream & operator<<(M2Stream &os, const char *val)
{
cout << "M2Stream good operator<<(const char *) called with " << val << endl;
return os;
}
int main(int argc, char argv[])
{
// This line calls void * overload, outputs: M2Stream bad operator<<(void *) called with literal char string on constructed temporary
M2Stream() << "literal char string on constructed temporary";
const char *s = "char string variable";
// This line calls the const char * overload, and outputs: M2Stream good operator<<(const char *) called with char string variable
M2Stream() << s;
// This line calls the const char * overload, and outputs: M2Stream good operator<<(const char *) called with literal char string on prebuilt object
M2Stream m;
m << "literal char string on prebuilt object";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
M2Stream bad operator<<(void *) called with literal char string on constructed temporary
M2Stream good operator<<(const char *) called with char string variable
M2Stream good operator<<(const char *) called with literal char string on prebuilt object
Run Code Online (Sandbox Code Playgroud)
Joh*_*itb 10
编译器正在做正确的事情:Stream() << "hello";应该使用operator<<定义的成员函数.由于临时流对象不能绑定到非const引用,而只能绑定到const引用,因此char const*不会选择处理的非成员运算符.
正如您所知,当您更改该运算符时,它就是这样设计的.您会产生歧义,因为编译器无法决定使用哪些可用的运算符.因为所有这些都是operator<<针对临时工而设计的,拒绝非成员.
然后,是的,字符串文字的类型不同于char const*.字符串文字是一个const字符数组.但是,我想,这对你的情况无关紧要.我不知道operator<<MSVC++的重载是什么.只要它们不影响有效程序的行为,就允许添加进一步的重载.
为什么M2Stream() << s;即使第一个参数是非const引用也能正常工作......好吧,MSVC++有一个扩展,允许非const引用绑定到temporaries.将警告级别置于级别4以查看有关该级别的警告(类似"使用的非标准扩展......").
现在,因为有一个成员运算符<<取一个void const*,并且char const*可以转换为该运算符,所以将选择该运算符,并输出该地址作为void const*重载的内容.
我在你的代码中看到你实际上有一个void*重载,而不是void const*重载.好吧,字符串文字可以转换为char*,即使字符串文字的类型是char const[N](N是您放置的字符数).但该转换已被弃用.它应该不是字符串文字转换为的标准void*.在我看来,这是MSVC++编译器的另一个扩展.但这可以解释为什么字符串文字的处理方式与char const*指针不同.这就是标准所说的:
不是宽字符串文字的字符串文字(2.13.4)可以转换为"指向字符的指针"的右值; 可以将宽字符串文字转换为"指向wchar_t的指针"类型的右值.在任何一种情况下,结果都是指向数组第一个元素的指针.仅当存在明确的适当指针目标类型时才考虑此转换,而不是在通常需要从左值转换为右值时.[注意:此转换已弃用.见附件D.]
第一个问题是由奇怪而棘手的C++语言规则引起的:
发生的事情是ostream& operator<<(ostream&, const char*),非成员函数尝试将M2Stream您创建的临时绑定绑定到非const引用,但是失败(规则#2); 但是ostream& ostream::operator<<(void*)是一个成员函数,因此可以绑定它.在没有该const char*功能的情况下,它被选为最佳过载.
我不知道为什么Iostreams库的设计者决定做operator<<()了void*一个方法,但不是operator<<()对const char*,但是这是怎么回事,所以我们有这些奇怪的矛盾来处理.
我不确定为什么会出现第二个问题.您是否在不同的编译器中获得相同的行为?它可能是编译器或C++标准库的错误,但我会把它作为最后的借口 - 至少看看你是否可以ostream先定期复制行为.
| 归档时间: |
|
| 查看次数: |
1543 次 |
| 最近记录: |