I have a template class and a custom std::formatter
specialization for that class to be able to format and print it. When I create this class with std::errc
data and try to print it, the compiler complains:
error: no match for 'operator<<' (operand types are 'std::ostringstream' {aka 'std::__cxx11::basic_ostringstream<char>'} and 'const std::errc')
59 | oss << my_class.data();
The compile error is because it cannot detect the operator<<
overload that I created for std::errc
. When I try to print a std::errc
instance directly in main()
, it can find and run the operator<<
overload that I created and prints the correct data.
#include <format>
#include <iostream>
#include <sstream>
#include <string>
#include <system_error>
template <typename DATA_T>
class MyClass {
public:
MyClass(std::string name, DATA_T data, std::string location)
: name_(std::move(name)),
data_(std::move(data)),
location_(std::move(location)) {}
const std::string& name() const { return name_; }
const DATA_T& data() const { return data_; }
const std::string& location() const { return location_; }
private:
std::string name_;
DATA_T data_;
std::string location_;
};
// Specialization for std::errc for std::format
template <>
struct std::formatter<std::errc> : std::formatter<std::string> {
static auto format(const std::errc& err, std::format_context& ctx) {
auto error_code = std::make_error_code(err);
return std::format_to(ctx.out(), "Error {}: {}", error_code.value(),
error_code.message());
}
};
// Overload operator<< for std::errc
inline std::ostream& operator<<(std::ostream& ostr, const std::errc& err) {
return ostr << std::format("{}", err);
}
// Custom concept to check if a type is streamable via operator<<
template <typename T>
concept OStreamable = requires(std::ostream& os, const T& t) {
{ os << t } -> std::convertible_to<std::ostream&>;
};
// Specialization for MyClass for std::format
template <typename DATA_T>
struct std::formatter<MyClass<DATA_T>> : std::formatter<std::string> {
auto format(const MyClass<DATA_T>& my_class,
std::format_context& ctx) const {
std::string result = std::format("Name: {}\n", my_class.name());
// Check if DATA_T is streamable
if constexpr (OStreamable<DATA_T>) {
std::ostringstream oss;
oss << my_class.data();
result += "Data: " + oss.str();
}
result += std::format("\nLocation: {}", my_class.location());
return std::format_to(ctx.out(), "{}", result);
}
};
// Overload operator<< for MyClass
template <typename T>
inline std::ostream& operator<<(std::ostream& ostr,
const MyClass<T>& my_class) {
return ostr << std::format("{}", my_class);
}
int main() {
MyClass<std::errc> my_class{"Errc Object", std::errc::invalid_argument,
"Main Frame"};
std::cout << std::errc::invalid_argument << '\n'; // Works fine
// std::println("{}", my_class); // Creates a compile error.
}
If I add using ::operator<<
statement before oss << my_class.data()
, the compile error is gone.
How is it possible that the operator<<
overload can be found when it is called in main()
but cannot be found in my std::formatter
specialization? Is there a way to fix it without adding a using ::operator<<
statement?
The complete compiler error:
<source>:60:17: error: invalid operands to binary expression ('std::ostringstream' (aka 'basic_ostringstream<char>') and 'const std::errc')
60 | oss << my_class.data();
| ~~~ ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2529:14: note: in instantiation of member function 'std::formatter<MyClass<std::errc>>::format' requested here
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2529:9: note: in instantiation of requirement here
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ^~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2527:7: note: while substituting template arguments into constraint expression here
2527 | && requires (const _Formatter __cf, _Tp&& __t, _Context __fc)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2528 | {
| ~
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2530 | };
| ~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3475:11: note: while checking the satisfaction of concept '__formattable_with<MyClass<std::errc>, std::basic_format_context<std::__format::_Sink_iter<char>, char>, std::formatter<MyClass<std::errc>>, std::basic_format_parse_context<char>>' requested here
3475 | requires __format::__formattable_with<_Tp, _Context>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3475:11: note: while substituting template arguments into constraint expression here
3475 | requires __format::__formattable_with<_Tp, _Context>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3743:31: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
3743 | basic_format_arg<_Context> __arg(__v);
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3754:12: note: in instantiation of function template specialization 'std::__format::_Arg_store<std::basic_format_context<std::__format::_Sink_iter<char>, char>, std::basic_format_arg<std::basic_format_context<std::__format::_Sink_iter<char>, char>>::handle>::_S_make_elt<MyClass<std::errc>>' requested here
3754 | : _M_args{_S_make_elt(__a)...}
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3804:14: note: in instantiation of function template specialization 'std::__format::_Arg_store<std::basic_format_context<std::__format::_Sink_iter<char>, char>, std::basic_format_arg<std::basic_format_context<std::__format::_Sink_iter<char>, char>>::handle>::_Arg_store<MyClass<std::errc>>' requested here
3804 | return _Store(__fmt_args...);
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/print:123:9: note: in instantiation of function template specialization 'std::format<MyClass<std::errc> &>' requested here
123 | std::format(__fmt, std::forward<_Args>(__args)...));
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/print:129:12: note: in instantiation of function template specialization 'std::println<MyClass<std::errc> &>' requested here
129 | { std::println(stdout, __fmt, std::forward<_Args>(__args)...); }
| ^
<source>:78:10: note: in instantiation of function template specialization 'std::println<MyClass<std::errc> &>' requested here
78 | std::println("{}", my_class); // Creates a compile error.
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/system_error:339:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const error_code' for 2nd argument
339 | operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e)
| ^ ~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:570:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char' for 2nd argument
570 | operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:576:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char' for 2nd argument
576 | operator<<(basic_ostream<char, _Traits>& __out, char __c)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:587:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'signed char' for 2nd argument
587 | operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:592:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'unsigned char' for 2nd argument
592 | operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
| ^ ~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:601:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'wchar_t' for 2nd argument
601 | operator<<(basic_ostream<char, _Traits>&, wchar_t) = delete;
| ^ ~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:606:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char8_t' for 2nd argument
606 | operator<<(basic_ostream<char, _Traits>&, char8_t) = delete;
| ^ ~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:611:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char16_t' for 2nd argument
611 | operator<<(basic_ostream<char, _Traits>&, char16_t) = delete;
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:615:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char32_t' for 2nd argument
615 | operator<<(basic_ostream<char, _Traits>&, char32_t) = delete;
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:668:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char *' for 2nd argument
668 | operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:681:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const signed char *' for 2nd argument
681 | operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
| ^ ~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:686:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const unsigned char *' for 2nd argument
686 | operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:695:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const wchar_t *' for 2nd argument
695 | operator<<(basic_ostream<char, _Traits>&, const wchar_t*) = delete;
| ^ ~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:700:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char8_t *' for 2nd argument
700 | operator<<(basic_ostream<char, _Traits>&, const char8_t*) = delete;
| ^ ~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:705:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char16_t *' for 2nd argument
705 | operator<<(basic_ostream<char, _Traits>&, const char16_t*) = delete;
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:709:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char32_t *' for 2nd argument
709 | operator<<(basic_ostream<char, _Traits>&, const char32_t*) = delete;
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/bits/ostream.tcc:307:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char *' for 2nd argument
307 | operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/cstddef:125:5: note: candidate function template not viable: no known conversion from 'std::ostringstream' (aka 'basic_ostringstream<char>') to 'byte' for 1st argument
125 | operator<<(byte __b, _IntegerType __shift) noexcept
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:560:5: note: candidate template ignored: deduced conflicting types for parameter '_CharT' ('char' vs. 'std::errc')
560 | operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/string_view:760:5: note: candidate template ignored: could not match 'basic_string_view<_CharT, _Traits>' against 'std::errc'
760 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/bits/basic_string.h:4077:5: note: candidate template ignored: could not match 'const basic_string<_CharT, _Traits, _Alloc>' against 'const std::errc'
4077 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:621:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
621 | operator<<(basic_ostream<wchar_t, _Traits>&, char8_t) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:626:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
626 | operator<<(basic_ostream<wchar_t, _Traits>&, char16_t) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:630:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
630 | operator<<(basic_ostream<wchar_t, _Traits>&, char32_t) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:651:5: note: candidate template ignored: could not match 'const _CharT *' against 'std::errc'
651 | operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:715:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
715 | operator<<(basic_ostream<wchar_t, _Traits>&, const char8_t*) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:720:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
720 | operator<<(basic_ostream<wchar_t, _Traits>&, const char16_t*) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:724:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
724 | operator<<(basic_ostream<wchar_t, _Traits>&, const char32_t*) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:807:5: note: candidate template ignored: substitution failure [with _Ostream = std::ostringstream &, _Tp = std::errc]: constraints not satisfied for alias template '__rvalue_stream_insertion_t' [with _Os = std::basic_ostringstream<char> &, _Tp = std::errc]
806 | inline __rvalue_stream_insertion_t<_Ostream, _Tp>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
807 | operator<<(_Ostream&& __os, const _Tp& __x)
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:116:7: note: candidate function not viable: no known conversion from 'const std::errc' to '__ostream_type &(*)(__ostream_type &)' (aka 'basic_ostream<char, std::char_traits<char>> &(*)(basic_ostream<char, std::char_traits<char>> &)') for 1st argument
116 | operator<<(__ostream_type& (*__pf)(__ostream_type&))
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:125:7: note: candidate function not viable: no known conversion from 'const std::errc' to '__ios_type &(*)(__ios_type &)' (aka 'basic_ios<char, std::char_traits<char>> &(*)(basic_ios<char, std::char_traits<char>> &)') for 1st argument
125 | operator<<(__ios_type& (*__pf)(__ios_type&))
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:135:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'ios_base &(*)(ios_base &)' for 1st argument
135 | operator<<(ios_base& (*__pf) (ios_base&))
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:174:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'long' for 1st argument
174 | operator<<(long __n)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:178:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned long' for 1st argument
178 | operator<<(unsigned long __n)
| ^ ~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:182:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'bool' for 1st argument
182 | operator<<(bool __n)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:186:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'short' for 1st argument
186 | operator<<(short __n);
| ^ ~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:189:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned short' for 1st argument
189 | operator<<(unsigned short __n)
| ^ ~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:197:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'int' for 1st argument
197 | operator<<(int __n);
| ^ ~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:200:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned int' for 1st argument
200 | operator<<(unsigned int __n)
| ^ ~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:209:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'long long' for 1st argument
209 | operator<<(long long __n)
| ^ ~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:213:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned long long' for 1st argument
213 | operator<<(unsigned long long __n)
| ^ ~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:228:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'double' for 1st argument
228 | operator<<(double __f)
| ^ ~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:232:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'float' for 1st argument
232 | operator<<(float __f)
| ^ ~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:240:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'long double' for 1st argument
240 | operator<<(long double __f)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:298:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'const void *' for 1st argument; take the address of the argument with &
298 | operator<<(const void* __p)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:303:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'nullptr_t' (aka 'std::nullptr_t') for 1st argument
303 | operator<<(nullptr_t)
| ^ ~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:310:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'const volatile void *' for 1st argument; take the address of the argument with &
310 | operator<<(const volatile void* __p)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:336:7: note: candidate function not viable: no known conversion from 'const std::errc' to '__streambuf_type *' (aka 'basic_streambuf<char, std::char_traits<char>> *') for 1st argument
336 | operator<<(__streambuf_type* __sb);
| ^ ~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Compiler returned: 1
The full code and compile error can be seen at:
I have a template class and a custom std::formatter
specialization for that class to be able to format and print it. When I create this class with std::errc
data and try to print it, the compiler complains:
error: no match for 'operator<<' (operand types are 'std::ostringstream' {aka 'std::__cxx11::basic_ostringstream<char>'} and 'const std::errc')
59 | oss << my_class.data();
The compile error is because it cannot detect the operator<<
overload that I created for std::errc
. When I try to print a std::errc
instance directly in main()
, it can find and run the operator<<
overload that I created and prints the correct data.
#include <format>
#include <iostream>
#include <sstream>
#include <string>
#include <system_error>
template <typename DATA_T>
class MyClass {
public:
MyClass(std::string name, DATA_T data, std::string location)
: name_(std::move(name)),
data_(std::move(data)),
location_(std::move(location)) {}
const std::string& name() const { return name_; }
const DATA_T& data() const { return data_; }
const std::string& location() const { return location_; }
private:
std::string name_;
DATA_T data_;
std::string location_;
};
// Specialization for std::errc for std::format
template <>
struct std::formatter<std::errc> : std::formatter<std::string> {
static auto format(const std::errc& err, std::format_context& ctx) {
auto error_code = std::make_error_code(err);
return std::format_to(ctx.out(), "Error {}: {}", error_code.value(),
error_code.message());
}
};
// Overload operator<< for std::errc
inline std::ostream& operator<<(std::ostream& ostr, const std::errc& err) {
return ostr << std::format("{}", err);
}
// Custom concept to check if a type is streamable via operator<<
template <typename T>
concept OStreamable = requires(std::ostream& os, const T& t) {
{ os << t } -> std::convertible_to<std::ostream&>;
};
// Specialization for MyClass for std::format
template <typename DATA_T>
struct std::formatter<MyClass<DATA_T>> : std::formatter<std::string> {
auto format(const MyClass<DATA_T>& my_class,
std::format_context& ctx) const {
std::string result = std::format("Name: {}\n", my_class.name());
// Check if DATA_T is streamable
if constexpr (OStreamable<DATA_T>) {
std::ostringstream oss;
oss << my_class.data();
result += "Data: " + oss.str();
}
result += std::format("\nLocation: {}", my_class.location());
return std::format_to(ctx.out(), "{}", result);
}
};
// Overload operator<< for MyClass
template <typename T>
inline std::ostream& operator<<(std::ostream& ostr,
const MyClass<T>& my_class) {
return ostr << std::format("{}", my_class);
}
int main() {
MyClass<std::errc> my_class{"Errc Object", std::errc::invalid_argument,
"Main Frame"};
std::cout << std::errc::invalid_argument << '\n'; // Works fine
// std::println("{}", my_class); // Creates a compile error.
}
If I add using ::operator<<
statement before oss << my_class.data()
, the compile error is gone.
How is it possible that the operator<<
overload can be found when it is called in main()
but cannot be found in my std::formatter
specialization? Is there a way to fix it without adding a using ::operator<<
statement?
The complete compiler error:
<source>:60:17: error: invalid operands to binary expression ('std::ostringstream' (aka 'basic_ostringstream<char>') and 'const std::errc')
60 | oss << my_class.data();
| ~~~ ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2529:14: note: in instantiation of member function 'std::formatter<MyClass<std::errc>>::format' requested here
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2529:9: note: in instantiation of requirement here
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ^~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2527:7: note: while substituting template arguments into constraint expression here
2527 | && requires (const _Formatter __cf, _Tp&& __t, _Context __fc)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2528 | {
| ~
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2530 | };
| ~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3475:11: note: while checking the satisfaction of concept '__formattable_with<MyClass<std::errc>, std::basic_format_context<std::__format::_Sink_iter<char>, char>, std::formatter<MyClass<std::errc>>, std::basic_format_parse_context<char>>' requested here
3475 | requires __format::__formattable_with<_Tp, _Context>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3475:11: note: while substituting template arguments into constraint expression here
3475 | requires __format::__formattable_with<_Tp, _Context>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3743:31: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
3743 | basic_format_arg<_Context> __arg(__v);
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3754:12: note: in instantiation of function template specialization 'std::__format::_Arg_store<std::basic_format_context<std::__format::_Sink_iter<char>, char>, std::basic_format_arg<std::basic_format_context<std::__format::_Sink_iter<char>, char>>::handle>::_S_make_elt<MyClass<std::errc>>' requested here
3754 | : _M_args{_S_make_elt(__a)...}
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:3804:14: note: in instantiation of function template specialization 'std::__format::_Arg_store<std::basic_format_context<std::__format::_Sink_iter<char>, char>, std::basic_format_arg<std::basic_format_context<std::__format::_Sink_iter<char>, char>>::handle>::_Arg_store<MyClass<std::errc>>' requested here
3804 | return _Store(__fmt_args...);
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/print:123:9: note: in instantiation of function template specialization 'std::format<MyClass<std::errc> &>' requested here
123 | std::format(__fmt, std::forward<_Args>(__args)...));
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/print:129:12: note: in instantiation of function template specialization 'std::println<MyClass<std::errc> &>' requested here
129 | { std::println(stdout, __fmt, std::forward<_Args>(__args)...); }
| ^
<source>:78:10: note: in instantiation of function template specialization 'std::println<MyClass<std::errc> &>' requested here
78 | std::println("{}", my_class); // Creates a compile error.
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/system_error:339:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const error_code' for 2nd argument
339 | operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __e)
| ^ ~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:570:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char' for 2nd argument
570 | operator<<(basic_ostream<_CharT, _Traits>& __out, char __c)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:576:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char' for 2nd argument
576 | operator<<(basic_ostream<char, _Traits>& __out, char __c)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:587:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'signed char' for 2nd argument
587 | operator<<(basic_ostream<char, _Traits>& __out, signed char __c)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:592:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'unsigned char' for 2nd argument
592 | operator<<(basic_ostream<char, _Traits>& __out, unsigned char __c)
| ^ ~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:601:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'wchar_t' for 2nd argument
601 | operator<<(basic_ostream<char, _Traits>&, wchar_t) = delete;
| ^ ~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:606:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char8_t' for 2nd argument
606 | operator<<(basic_ostream<char, _Traits>&, char8_t) = delete;
| ^ ~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:611:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char16_t' for 2nd argument
611 | operator<<(basic_ostream<char, _Traits>&, char16_t) = delete;
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:615:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'char32_t' for 2nd argument
615 | operator<<(basic_ostream<char, _Traits>&, char32_t) = delete;
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:668:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char *' for 2nd argument
668 | operator<<(basic_ostream<char, _Traits>& __out, const char* __s)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:681:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const signed char *' for 2nd argument
681 | operator<<(basic_ostream<char, _Traits>& __out, const signed char* __s)
| ^ ~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:686:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const unsigned char *' for 2nd argument
686 | operator<<(basic_ostream<char, _Traits>& __out, const unsigned char* __s)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:695:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const wchar_t *' for 2nd argument
695 | operator<<(basic_ostream<char, _Traits>&, const wchar_t*) = delete;
| ^ ~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:700:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char8_t *' for 2nd argument
700 | operator<<(basic_ostream<char, _Traits>&, const char8_t*) = delete;
| ^ ~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:705:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char16_t *' for 2nd argument
705 | operator<<(basic_ostream<char, _Traits>&, const char16_t*) = delete;
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:709:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char32_t *' for 2nd argument
709 | operator<<(basic_ostream<char, _Traits>&, const char32_t*) = delete;
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/bits/ostream.tcc:307:5: note: candidate function template not viable: no known conversion from 'const std::errc' to 'const char *' for 2nd argument
307 | operator<<(basic_ostream<_CharT, _Traits>& __out, const char* __s)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/cstddef:125:5: note: candidate function template not viable: no known conversion from 'std::ostringstream' (aka 'basic_ostringstream<char>') to 'byte' for 1st argument
125 | operator<<(byte __b, _IntegerType __shift) noexcept
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:560:5: note: candidate template ignored: deduced conflicting types for parameter '_CharT' ('char' vs. 'std::errc')
560 | operator<<(basic_ostream<_CharT, _Traits>& __out, _CharT __c)
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/string_view:760:5: note: candidate template ignored: could not match 'basic_string_view<_CharT, _Traits>' against 'std::errc'
760 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/bits/basic_string.h:4077:5: note: candidate template ignored: could not match 'const basic_string<_CharT, _Traits, _Alloc>' against 'const std::errc'
4077 | operator<<(basic_ostream<_CharT, _Traits>& __os,
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:621:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
621 | operator<<(basic_ostream<wchar_t, _Traits>&, char8_t) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:626:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
626 | operator<<(basic_ostream<wchar_t, _Traits>&, char16_t) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:630:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
630 | operator<<(basic_ostream<wchar_t, _Traits>&, char32_t) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:651:5: note: candidate template ignored: could not match 'const _CharT *' against 'std::errc'
651 | operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:715:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
715 | operator<<(basic_ostream<wchar_t, _Traits>&, const char8_t*) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:720:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
720 | operator<<(basic_ostream<wchar_t, _Traits>&, const char16_t*) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:724:5: note: candidate template ignored: could not match 'basic_ostream' against 'std::basic_ostringstream'
724 | operator<<(basic_ostream<wchar_t, _Traits>&, const char32_t*) = delete;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:807:5: note: candidate template ignored: substitution failure [with _Ostream = std::ostringstream &, _Tp = std::errc]: constraints not satisfied for alias template '__rvalue_stream_insertion_t' [with _Os = std::basic_ostringstream<char> &, _Tp = std::errc]
806 | inline __rvalue_stream_insertion_t<_Ostream, _Tp>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
807 | operator<<(_Ostream&& __os, const _Tp& __x)
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:116:7: note: candidate function not viable: no known conversion from 'const std::errc' to '__ostream_type &(*)(__ostream_type &)' (aka 'basic_ostream<char, std::char_traits<char>> &(*)(basic_ostream<char, std::char_traits<char>> &)') for 1st argument
116 | operator<<(__ostream_type& (*__pf)(__ostream_type&))
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:125:7: note: candidate function not viable: no known conversion from 'const std::errc' to '__ios_type &(*)(__ios_type &)' (aka 'basic_ios<char, std::char_traits<char>> &(*)(basic_ios<char, std::char_traits<char>> &)') for 1st argument
125 | operator<<(__ios_type& (*__pf)(__ios_type&))
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:135:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'ios_base &(*)(ios_base &)' for 1st argument
135 | operator<<(ios_base& (*__pf) (ios_base&))
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:174:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'long' for 1st argument
174 | operator<<(long __n)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:178:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned long' for 1st argument
178 | operator<<(unsigned long __n)
| ^ ~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:182:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'bool' for 1st argument
182 | operator<<(bool __n)
| ^ ~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:186:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'short' for 1st argument
186 | operator<<(short __n);
| ^ ~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:189:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned short' for 1st argument
189 | operator<<(unsigned short __n)
| ^ ~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:197:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'int' for 1st argument
197 | operator<<(int __n);
| ^ ~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:200:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned int' for 1st argument
200 | operator<<(unsigned int __n)
| ^ ~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:209:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'long long' for 1st argument
209 | operator<<(long long __n)
| ^ ~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:213:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'unsigned long long' for 1st argument
213 | operator<<(unsigned long long __n)
| ^ ~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:228:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'double' for 1st argument
228 | operator<<(double __f)
| ^ ~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:232:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'float' for 1st argument
232 | operator<<(float __f)
| ^ ~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:240:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'long double' for 1st argument
240 | operator<<(long double __f)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:298:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'const void *' for 1st argument; take the address of the argument with &
298 | operator<<(const void* __p)
| ^ ~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:303:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'nullptr_t' (aka 'std::nullptr_t') for 1st argument
303 | operator<<(nullptr_t)
| ^ ~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:310:7: note: candidate function not viable: no known conversion from 'const std::errc' to 'const volatile void *' for 1st argument; take the address of the argument with &
310 | operator<<(const volatile void* __p)
| ^ ~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:336:7: note: candidate function not viable: no known conversion from 'const std::errc' to '__streambuf_type *' (aka 'basic_streambuf<char, std::char_traits<char>> *') for 1st argument
336 | operator<<(__streambuf_type* __sb);
| ^ ~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Compiler returned: 1
The full code and compile error can be seen at: https://gcc.godbolt./z/vq7WP3xnq
Share Improve this question edited Mar 16 at 19:17 Remy Lebeau 601k36 gold badges507 silver badges850 bronze badges asked Mar 16 at 15:29 sakcakocasakcakoca 1194 bronze badges 12 | Show 7 more comments1 Answer
Reset to default 1The issue revolves around argument-dependent lookup (ADL) and how it works differently in these two contexts.
It fails because:
my_class.data()
returns aconst std::errc&
std::errc
is defined in thestd
namespaceYour
operator<<
overload is in the global namespaceADL doesn't find your overload because it's not in the same namespace as
std::errc
The key insight: ADL only considers functions in the same namespace as the arguments.
Your
operator<<
is in the global namespace, butstd::errc
is in thestd
namespace. ADL will only find operator overloads that are in thestd
namespace or in namespaces of classes that are arguments to the operatorMove your overload to the std namespace:
namespace std {
inline std::ostream& operator<<(std::ostream& ostr, const std::errc& err) {
return ostr << std::format("{}", err);
}
}
operator<<
is in global namespace. However, the call is from inside namespacestd
. So the compiler searches namespacestd
for functions namedoperator<<
- any functions, not necessarily those that match argument types - and only if it can't find any, then it would go up and search the enclosing namespace. Of course, there are plenty ofoperator<<
overloads in namespacestd
; so yours in global namespace is never found. – Igor Tandetnik Commented Mar 16 at 16:24std::
namespace since the customoperator<<
overload is not defined instd
namespace. How can it be an undefined behavior? @guard3 – sakcakoca Commented Mar 16 at 16:26operator<<
overload to the global namespace. It's triggered by addingstd::formatter<std::errc>
specialization. Specializing a class template from standard library is allowed only when at least one parameter is a user-defined type. – Igor Tandetnik Commented Mar 16 at 16:28operator<<
won't actually be called from inside the standard library, and so won't unexpectedly alter the standard-specified behavior. Whereas your specialization might and might. This is what the rule is protecting against. – Igor Tandetnik Commented Mar 16 at 19:56