免责声明:我知道应避免隐式转换为字符串,并且正确的方法是op<<
Person
重载
请考虑以下代码:
#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;
}
yields the following on 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?
答案 0 :(得分:18)
14.8.1 / 4 in C ++ 98
如果参数类型不包含参与模板参数推导的 template-parameters ,则将对函数参数执行隐式转换(第4节)以将其转换为相应函数参数的类型。
在这里,您希望实例化
template <class charT, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>&,
const basic_string<charT, traits, Allocator>&);
在不明确提供任何模板参数的情况下推断出来。因此,所有参数都包含参与模板参数推导的 template-parameter ,因此它们都不能从隐式转换中获取其值。
答案 1 :(得分:7)
这是因为它是一个模板。
为此,您需要先实例化模板,然后再使用转换运算符。这是错误的顺序,所以它不起作用。
如果您之前在程序中使用过特定的操作符,则无关紧要。每次使用都单独考虑
作为候选者的重载是那些可以从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
答案 2 :(得分:2)
因为在ADL中不考虑用户定义的转换函数。 ADL表示重载集包含来自定义参数的命名空间的重载函数。这里operator<<
的参数的类型是NameType
,但operator << (std::ostream&, const NameType&)
尚未在定义NameType
的命名空间中定义。因此,错误,因为在那里搜索适当的重载停止。这就是ADL。 ADL没有进一步研究NameType
的定义,以确定它是否定义了任何用户定义的转换函数。
如果您执行以下操作,您将获得the same error:
NameType name;
std::cout << name ; //error: user-defined conversion not considered.
您需要cast:
std::cout << (std::string)name << std::endl; //ok - use std::string()
此外,您可能有多个用户定义的转换函数:
std::cout << (int)name << std::endl; //ok - use int() instead
ideone的输出:
wobble
100
答案 3 :(得分:0)
只有在某些情况下才会调用转换为字符串:
a)明确要求(string) p.name
b)分配给字符串string a = p.name
c)......
如果本案不符合任何规定,您可以通过至少两种方式强制调用ostream<<(ostream&,string)
:
http://ideone.com/SJe5W使NameType 成为字符串(通过公共继承)。
转到案例 a):明确请求转化,如转换为(int)
的示例所示。
我真的更喜欢选项 1 。
答案 4 :(得分:-3)
那是因为用户定义的转换无法链接。用一个例子来解释:
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"
这是similar question,我有时会回答。
在您的情况下,您的第一个用户定义的转化次数为
(1)NameType::operator std::string()
(2)operator <<(ostream&, const std::string&)
有点像ostream::operator<<(std::string&)
。
当你写作时,cout << p.name;
现在有两种类型的对象面对面:
ostream (LHS) <====> NameType (RHS)
现在,如果RHS为operator <<(ostream&, const string&)
,则string
仅会调用 。但这里是NameType
;所以它没有被调用。
如果LHS为NameType::operator string ()
,则string
仅会被调用。但这里是ostream
;所以它没有被调用。
使这个等式成立; bot应该由编译器调用上述运算符方法。但是C ++不支持。为什么它不受支持,在我上面发布的链接中有描述。