为什么下面的代码是由MSVC编译的,而不是GCC?
#include <iostream>
#include <sstream>
template <class C>
class basic_format
{
public:
template <typename T>
basic_format & operator << (const T & val)
{
out << val;
return *this;
}
std::basic_string<C> str() const { return out.str(); }
operator std::basic_string<C>() const { return str(); }
private:
std::basic_ostringstream<C> out;
};
using aformat = basic_format<char>;
using wformat = basic_format<wchar_t>;
namespace other
{
class A {};
}
template <class C>
std::basic_ostream<C>& operator << (std::basic_ostream<C>& out, const other::A&)
{
return out << static_cast<C>('A');
}
int main()
{
other::A a;
const std::string val = aformat() << a;
std::cout << val << std::endl;
return 0;
}
GCC 12错误:
g++ -std=c++20 -pthread a.cpp -o a
a.cpp: In instantiation of ‘basic_format<C>& basic_format<C>::operator<<(const T&) [with T = other::A; C = char]’:
a.cpp:43:42: required from here
a.cpp:12:13: error: no match for ‘operator<<’ (operand types are ‘std::__cxx11::basic_ostringstream<char>’ and ‘const other::A’)
12 | out << val;
| ~~~~^~~~~~
In file included from /usr/include/c++/12/iostream:39,
from a.cpp:1:
/usr/include/c++/12/ostream:108:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(__ostream_type& (*)(__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
108 | operator<<(__ostream_type& (*__pf)(__ostream_type&))
| ^~~~~~~~
/usr/include/c++/12/ostream:108:36: note: no known conversion for argument 1 from ‘const other::A’ to ‘std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&)’ {aka ‘std::basic_ostream<char>& (*)(std::basic_ostream<char>&)’}
108 | operator<<(__ostream_type& (*__pf)(__ostream_type&))
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/12/ostream:117:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(__ios_type& (*)(__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>; __ios_type = std::basic_ios<char>]’
117 | operator<<(__ios_type& (*__pf)(__ios_type&))
| ^~~~~~~~
/usr/include/c++/12/ostream:117:32: note: no known conversion for argument 1 from ‘const other::A’ to ‘std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&)’ {aka ‘std::basic_ios<char>& (*)(std::basic_ios<char>&)’}
117 | operator<<(__ios_type& (*__pf)(__ios_type&))
| ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
/usr/include/c++/12/ostream:127:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
127 | operator<<(ios_base& (*__pf) (ios_base&))
| ^~~~~~~~
/usr/include/c++/12/ostream:127:30: note: no known conversion for argument 1 from ‘const other::A’ to ‘std::ios_base& (*)(std::ios_base&)’
127 | operator<<(ios_base& (*__pf) (ios_base&))
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~
/usr/include/c++/12/ostream:166:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
166 | operator<<(long __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:166:23: note: no known conversion for argument 1 from ‘const other::A’ to ‘long int’
166 | operator<<(long __n)
| ~~~~~^~~
/usr/include/c++/12/ostream:170:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
170 | operator<<(unsigned long __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:170:32: note: no known conversion for argument 1 from ‘const other::A’ to ‘long unsigned int’
170 | operator<<(unsigned long __n)
| ~~~~~~~~~~~~~~^~~
/usr/include/c++/12/ostream:174:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
174 | operator<<(bool __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:174:23: note: no known conversion for argument 1 from ‘const other::A’ to ‘bool’
174 | operator<<(bool __n)
| ~~~~~^~~
In file included from /usr/include/c++/12/ostream:833:
/usr/include/c++/12/bits/ostream.tcc:91:5: note: candidate: ‘std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]’
91 | basic_ostream<_CharT, _Traits>::
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/12/bits/ostream.tcc:92:22: note: no known conversion for argument 1 from ‘const other::A’ to ‘short int’
92 | operator<<(short __n)
| ~~~~~~^~~
/usr/include/c++/12/ostream:181:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
181 | operator<<(unsigned short __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:181:33: note: no known conversion for argument 1 from ‘const other::A’ to ‘short unsigned int’
181 | operator<<(unsigned short __n)
| ~~~~~~~~~~~~~~~^~~
/usr/include/c++/12/bits/ostream.tcc:105:5: note: candidate: ‘std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]’
105 | basic_ostream<_CharT, _Traits>::
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/12/bits/ostream.tcc:106:20: note: no known conversion for argument 1 from ‘const other::A’ to ‘int’
106 | operator<<(int __n)
| ~~~~^~~
/usr/include/c++/12/ostream:192:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
192 | operator<<(unsigned int __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:192:31: note: no known conversion for argument 1 from ‘const other::A’ to ‘unsigned int’
192 | operator<<(unsigned int __n)
| ~~~~~~~~~~~~~^~~
/usr/include/c++/12/ostream:201:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
201 | operator<<(long long __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:201:28: note: no known conversion for argument 1 from ‘const other::A’ to ‘long long int’
201 | operator<<(long long __n)
| ~~~~~~~~~~^~~
/usr/include/c++/12/ostream:205:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
205 | operator<<(unsigned long long __n)
| ^~~~~~~~
/usr/include/c++/12/ostream:205:37: note: no known conversion for argument 1 from ‘const other::A’ to ‘long long unsigned int’
205 | operator<<(unsigned long long __n)
| ~~~~~~~~~~~~~~~~~~~^~~
/usr/include/c++/12/ostream:220:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
220 | operator<<(double __f)
| ^~~~~~~~
/usr/include/c++/12/ostream:220:25: note: no known conversion for argument 1 from ‘const other::A’ to ‘double’
220 | operator<<(double __f)
| ~~~~~~~^~~
/usr/include/c++/12/ostream:224:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
224 | operator<<(float __f)
| ^~~~~~~~
/usr/include/c++/12/ostream:224:24: note: no known conversion for argument 1 from ‘const other::A’ to ‘float’
224 | operator<<(float __f)
| ~~~~~~^~~
/usr/include/c++/12/ostream:232:7: note: candidate: ‘std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; __ostream_type = std::basic_ostream<char>]’
232 | operator<<(long double __f)
| ^~~~~~~~
/usr/include/c++/12/ostream:232:30: note: no known conversion for argument 1 from ‘const other::A’ to ‘long double’
但是如果我在命名空间之外(在全局级别)声明class A
,它就会开始被GCC编译。
1条答案
按热度按时间ajsxfq5m1#
GCC是正确的。默认情况下,MSVC在模板定义中有不符合标准的查找规则(我假设可以通过
/permissive-
或将语言设置为C++20或更高版本来禁用,这显然是不正确的)。一个只在模板定义后 * 声明的函数,只能在模板参数推导中通过从模板示例化的Angular 进行依赖于参数的查找来考虑,而不是通过从示例化的Angular 进行通常的非限定查找。
所以对于
out << val
,全局命名空间范围内的
operator<<
重载只能通过ADL来考虑。ADL只考虑与参数/操作数(或其他关联类型)所在的名称空间范围相同的声明。
这就是为什么非成员运算符重载总是与它所作用的类(模板)属于同一个命名空间范围的原因。