Given the following code:
#include <iostream>
#include <functional>
#include <utility>
template<class O, class T, class = void>
constexpr bool ostreamable_with = false;
template<class O, class T>
constexpr bool ostreamable_with<
O, T, std::void_t<decltype(operator<<(std::declval<O>(),
std::declval<T>()))>> = true;
struct jostream : std::reference_wrapper<std::ostream>
{
using reference_wrapper::reference_wrapper;
std::ostream& os() { return *this; }
template<class T>
jostream& operator<<(T const& v)
{
if constexpr(ostreamable_with<jostream&, T const&>)
operator<<(*this, v);
else
os() << v;
return *this;
}
};
namespace user {
struct C
{ int a; };
inline jostream& operator<<(jostream& os, C const& c)
{ return os << c.a; }
}
int main()
{
jostream jos(std::cout);
user::C u{1};
jos << std::cref(u);
}
There #1
is a compiler error in the line , because it jostream
has a member of the function with the name operator<<
, so the call in the line #1
(the commented line inside jostream::operator<<
, not the first line of code) tries to make an explicit call jostream::operator<<
with two parameters that do not exist.
Is there any trick to force a call to a non-member function with colliding names? (other than calling an external function that makes the actual call). A ::operator<<
call is clearly not the solution here because overloading may be inside the user namespace, as the example shows.
(using gcc-7.2.0)