This simple code can be compiled by clang++, but not with g++. Is there anything undefined in it? (the template function is needed to make clang happy) GCC 8.2.0 (used with -std=c++17) says operator<< is ambiguous, it shows a list of candidates, but my template function is not even among them.
#include <cstddef>
#include <utility>
#include <sstream>
template<class Out>
Out&& operator<<(Out&& out, std::nullptr_t) {
out << "nullptr";
return std::forward<Out>(out); }
struct A : std::stringstream { };
int main() {
A{} << nullptr;
}
I believe this is caused by Bug 51577 of GCC.
Your code results in the instantiation of std::__is_insertable<std::basic_ostream<char>&, std::nullptr_t&, void>
in libstdc++, then let's look at the definition of this struct:
template<typename _Ostream, typename _Tp, typename = void>
struct __is_insertable : false_type {};
template<typename _Ostream, typename _Tp>
struct __is_insertable<_Ostream, _Tp,
__void_t<decltype(declval<_Ostream&>()
<< declval<const _Tp&>())>>
: true_type {};
If everything goes right, your operator<<
is invisible here1, then the partial specialization is disabled by SFINAE, and __is_insertable
is instantiated normally to be a derived class of std::false_type
.
Now due to Bug 51577, your operator<<
is visible here, causing the parital specialization to be a perfect match. However, when instantiating __is_insertable
, your operator<<
is invisible for some reason, so an error occurs because of ambiguous overload for operator<<
.
Note GCC 9 compiles this code. This is because there is a new overload
basic_ostream& operator<<( std::nullptr_t );
... added in C++17, so __is_insertable
can be successfully instantiated whether or not your operator<<
is visible. The bug is still there.
1 This is because [temp.dep.candidate]/1:
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup, only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either the template definition context or the template instantiation context are found.
Your operator<<
cannot be found from the template definition context of course. The arguments are of types std::basic_ostream<char>
and std::nullptr_t
, so the associated namespaces do not contain the global namespace. As a result, your operator<<
shouldn't be found.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With