通过隐式转换为字符串对对象进行流式处理时,重载解析失败
Overload resolution failure when streaming object via implicit conversion to string
免责声明:我知道应该避免隐式转换为字符串,正确的方法是Person
的op<<
重载。
考虑以下代码:
#include <string>
#include <ostream>
#include <iostream>
struct NameType {
operator std::string() { return "wobble"; }
};
struct Person {
NameType name;
};
int main() {
std::cout << std::string("bobble");
std::cout << "wibble";
Person p;
std::cout << p.name;
}
它在GCC 4.3.4中产生以下内容:
prog.cpp: In function ‘int main()’:
prog.cpp:18: error: no match for ‘operator<<’ in ‘std::cout << p.Person::name’
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:112: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:121: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:131: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:169: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:173: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:177: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:97: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:184: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:111: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:195: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:204: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:208: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:213: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:217: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:225: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:229: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:125: note: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]
为什么空闲的op<<(ostream&, string const&)
没有进入过载集?这是因为所需的重载是模板实例化和。。。ADL?
14.8.1/4在C++98 中
如果函数参数类型不包含参与模板参数推导的模板参数,则将对该函数参数执行隐式转换(第4条(,以将其转换为相应函数参数的类型。
这里你想要一个的实例化
template <class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&,
const basic_string<charT, traits, Allocator>&);
可以在不显式提供任何模板参数的情况下推导。因此,所有参数都包含一个参与模板参数推导的模板参数,因此没有一个参数可以从隐式转换中获得其值。
这是因为它是一个模板。
为了实现这一点,您需要首先实例化模板,然后使用转换运算符。这是错误的顺序,所以它不起作用。
在程序的早期是否使用了特定的运算符并不重要。每次使用都单独考虑
被认为是候选者的重载是那些所有模板参数都可以从std::ostream推导出来的重载,或者是那些属于该类的重载。
如果我们添加一个非模板运算符呢?
#include <string>
#include <ostream>
#include <iostream>
struct NameType {
operator std::string() { return "wobble"; }
};
struct Person {
NameType name;
};
void operator<<(std::ostream& os, const std::string& s) // ** added **
{ std::operator<<(os, s); }
int main()
{
std::cout << std::string("bobble");
std::cout << "wibble";
Person p;
std::cout << p.name;
}
现在它工作,并输出
bobblewibblewobble
这是因为ADL中没有考虑用户定义的转换函数。ADL表示重载集包含定义参数的命名空间中的重载函数。这里,operator<<
的参数的类型是NameType
,但operator << (std::ostream&, const NameType&)
尚未在定义NameType
的命名空间中定义。因此出现了错误,因为搜索适当的过载会立即停止。这就是ADL。ADL没有进一步研究NameType
的定义,以确定它是否定义了任何用户定义的转换函数。
如果您执行以下操作,您将得到相同的错误:
NameType name;
std::cout << name ; //error: user-defined conversion not considered.
你需要铸造它:
std::cout << (std::string)name << std::endl; //ok - use std::string()
此外,您可能有多个用户定义的转换函数:
std::cout << (int)name << std::endl; //ok - use int() instead
视频输出:
wobble
100
只有在以下情况下才会调用到字符串的转换:
a( 明确请求(string) p.name
b( 分配给字符串string a = p.name
c( 。。。
如果目前的情况不适合任何情况,您可以通过至少两种方式强制调用ostream<<(ostream&,string)
:
-
http://ideone.com/SJe5W使NameType成为字符串(通过公共继承(。
-
转到案例a(:明确请求转换,如转换为
(int)
的示例所示。
我真的更喜欢1这个选项。
这是因为用户定义的转换无法链接。举例说明:
struct A {
void operator = (const int i);
};
struct B {
operator int ();
}
A a;
B b;
a = b; // error! because, compiler will not match "A::operator=" and "B::operator int"
这是我以前问过的类似问题。
在您的情况下,您的第一个用户定义转换是
(1( NameType::operator std::string()
(2( operator <<(ostream&, const std::string&)
,有点像CCD_。
编写时,cout << p.name;
现在有两种类型的对象面对面:
ostream (LHS) <====> NameType (RHS)
现在,如果RHS是string
,则仅调用operator <<(ostream&, const string&)
。但这里是NameType
;所以它没有被调用。
并且,如果LHS是string
,则仅调用NameType::operator string ()
。但这里是ostream
;所以它没有被调用。
为了使这个方程式成立;上述运算符方法中的bot应该由编译器调用。但C++不支持这一点。我在上面发布的链接中描述了为什么不支持它。
- QDateTime::toString() 在退出处理程序中使用时失败
- 为什么此代码导致未处理的异常失败
- 生成库失败:无法识别文件格式;作为链接器脚本处理
- 构造函数中的错误处理而不会失败
- 在 Mac 上C++编译代码时处理“dyld:惰性符号绑定失败:找不到符号”错误
- 错误 opencv 错误断言失败 (p [-1] <= 2) 是什么意思以及如何处理它?
- boost::async_connect 上的 ASIO 完成处理程序在第一次失败后再也没有调用过
- 如何处理失败的方法:通过使用异常或使方法返回bool
- 我该如何处理断言失败
- 如何处理PostMessage()失败
- 如何处理 RAII 的构造函数失败
- 处理失败的构造函数
- vHRESULT 中未处理的异常失败
- C++自做异常处理失败
- 失败错误处理问题
- 程序在Turbo C中运行良好,但在MSVC中失败,出现未处理的异常
- 如何预期static_assert失败并使用Boost.Test框架进行处理
- 预处理失败了
- IDirect3DDevice9::GetFrontBufferData失败,分割错误.处理步骤
- c++异常处理失败