Home > Enterprise >  Issue with C ADL? Trying to create a universal map printer and this snippet won't compile
Issue with C ADL? Trying to create a universal map printer and this snippet won't compile

Time:07-12

Here is the full program.

I'm using clang 13 with -std=c 20 -stdlib=libc .

The error message, not included here because it's extremely long, basically says that the compiler does not even consider the operator<< function I've included here (error is on the std::cerr line near the end of the snippet).

#include <iostream>
#include <string>
#include <unordered_map>

template<typename K, typename V, typename ...Args>
std::ostream& operator<<(std::ostream& os, std::unordered_map<K, V, Args...> const& o) noexcept
{
    for (auto const& [k, v] : o)
        os << " " << k << ": " << v;
    return os;
}

namespace my_namespace
{
struct A
{
    std::unordered_map<int, std::string> map{{1, "hello"}, {2, "goodbye"}};
};

A a;

}

int main()
{
    std::cerr << my_namespace::a; // error is here
}

Here is the lengthy error message (sorry for not including it earlier):

file.cpp:25:15: error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'A')
    std::cerr << a;
    ~~~~~~~~~ ^  ~
/usr/lib/llvm-13/bin/../include/c  /v1/cstddef:141:3: note: candidate function template not viable: no known conversion from 'std::ostream' (aka 'basic_ostream<char>') to 'std::byte' for 1st argument
  operator<< (byte  __lhs, _Integer __shift) noexcept
  ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:748:1: note: candidate function template not viable: no known conversion from 'A' to 'char' for 2nd argument
operator<<(basic_ostream<_CharT, _Traits>& __os, char __cn)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:781:1: note: candidate function template not viable: no known conversion from 'A' to 'char' for 2nd argument
operator<<(basic_ostream<char, _Traits>& __os, char __c)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:788:1: note: candidate function template not viable: no known conversion from 'A' to 'signed char' for 2nd argument
operator<<(basic_ostream<char, _Traits>& __os, signed char __c)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:795:1: note: candidate function template not viable: no known conversion from 'A' to 'unsigned char' for 2nd argument
operator<<(basic_ostream<char, _Traits>& __os, unsigned char __c)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:809:1: note: candidate function template not viable: no known conversion from 'A' to 'const char *' for 2nd argument
operator<<(basic_ostream<_CharT, _Traits>& __os, const char* __strn)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:855:1: note: candidate function template not viable: no known conversion from 'A' to 'const char *' for 2nd argument
operator<<(basic_ostream<char, _Traits>& __os, const char* __str)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:862:1: note: candidate function template not viable: no known conversion from 'A' to 'const signed char *' for 2nd argument
operator<<(basic_ostream<char, _Traits>& __os, const signed char* __str)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:870:1: note: candidate function template not viable: no known conversion from 'A' to 'const unsigned char *' for 2nd argument
operator<<(basic_ostream<char, _Traits>& __os, const unsigned char* __str)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1055:1: note: candidate function template not viable: no known conversion from 'A' to 'const std::error_code' for 2nd argument
operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __ec)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:741:1: note: candidate template ignored: deduced conflicting types for parameter '_CharT' ('char' vs. 'A')
operator<<(basic_ostream<_CharT, _Traits>& __os, _CharT __c)
^
/usr/lib/llvm-13/bin/../include/c  /v1/__random/uniform_int_distribution.h:282:1: note: candidate template ignored: could not match 'uniform_int_distribution<type-parameter-0-2>' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:802:1: note: candidate template ignored: could not match 'const _CharT *' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os, const _CharT* __str)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1038:1: note: candidate template ignored: could not match 'basic_string<type-parameter-0-0, type-parameter-0-1, type-parameter-0-2>' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1046:1: note: candidate template ignored: could not match 'basic_string_view<type-parameter-0-0, type-parameter-0-1>' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1063:1: note: candidate template ignored: could not match 'shared_ptr<type-parameter-0-2>' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1082:1: note: candidate template ignored: could not match 'bitset<_Size>' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
^
file.cpp:6:15: note: candidate template ignored: could not match 'unordered_map<type-parameter-0-0, type-parameter-0-1, type-parameter-0-2...>' against 'A'
std::ostream& operator<<(std::ostream& os, std::unordered_map<K, V, Args...> const& o) noexcept
              ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1030:11: note: candidate template ignored: requirement 'integral_constant<bool, false>::value' was not satisfied [with _Stream = std::ostream &, _Tp = A]
_Stream&& operator<<(_Stream&& __os, const _Tp& __x)
          ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:1075:1: note: candidate template ignored: could not match 'unique_ptr<type-parameter-0-2, type-parameter-0-3>' against 'A'
operator<<(basic_ostream<_CharT, _Traits>& __os, unique_ptr<_Yp, _Dp> const& __p)
^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:188:20: note: candidate function not viable: no known conversion from 'A' to 'std::ostream &(*)(std::ostream &)' for 1st argument
    basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&))
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:192:20: note: candidate function not viable: no known conversion from 'A' to 'basic_ios<std::basic_ostream<char>::char_type, std::basic_ostream<char>::traits_type> &(*)(basic_ios<std::basic_ostream<char>::char_type, std::basic_ostream<char>::traits_type> &)' (aka 'basic_ios<char, std::char_traits<char>> &(*)(basic_ios<char, std::char_traits<char>> &)') for 1st argument
    basic_ostream& operator<<(basic_ios<char_type, traits_type>&
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:197:20: note: candidate function not viable: no known conversion from 'A' to 'std::ios_base &(*)(std::ios_base &)' for 1st argument
    basic_ostream& operator<<(ios_base& (*__pf)(ios_base&))
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:200:20: note: candidate function not viable: no known conversion from 'A' to 'bool' for 1st argument
    basic_ostream& operator<<(bool __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:201:20: note: candidate function not viable: no known conversion from 'A' to 'short' for 1st argument
    basic_ostream& operator<<(short __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:202:20: note: candidate function not viable: no known conversion from 'A' to 'unsigned short' for 1st argument
    basic_ostream& operator<<(unsigned short __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:203:20: note: candidate function not viable: no known conversion from 'A' to 'int' for 1st argument
    basic_ostream& operator<<(int __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:204:20: note: candidate function not viable: no known conversion from 'A' to 'unsigned int' for 1st argument
    basic_ostream& operator<<(unsigned int __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:205:20: note: candidate function not viable: no known conversion from 'A' to 'long' for 1st argument
    basic_ostream& operator<<(long __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:206:20: note: candidate function not viable: no known conversion from 'A' to 'unsigned long' for 1st argument
    basic_ostream& operator<<(unsigned long __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:207:20: note: candidate function not viable: no known conversion from 'A' to 'long long' for 1st argument
    basic_ostream& operator<<(long long __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:208:20: note: candidate function not viable: no known conversion from 'A' to 'unsigned long long' for 1st argument
    basic_ostream& operator<<(unsigned long long __n);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:209:20: note: candidate function not viable: no known conversion from 'A' to 'float' for 1st argument
    basic_ostream& operator<<(float __f);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:210:20: note: candidate function not viable: no known conversion from 'A' to 'double' for 1st argument
    basic_ostream& operator<<(double __f);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:211:20: note: candidate function not viable: no known conversion from 'A' to 'long double' for 1st argument
    basic_ostream& operator<<(long double __f);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:212:20: note: candidate function not viable: no known conversion from 'A' to 'const void *' for 1st argument; take the address of the argument with &
    basic_ostream& operator<<(const void* __p);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:213:20: note: candidate function not viable: no known conversion from 'A' to 'basic_streambuf<std::basic_ostream<char>::char_type, std::basic_ostream<char>::traits_type> *' (aka 'basic_streambuf<char, std::char_traits<char>> *') for 1st argument
    basic_ostream& operator<<(basic_streambuf<char_type, traits_type>* __sb);
                   ^
/usr/lib/llvm-13/bin/../include/c  /v1/ostream:216:20: note: candidate function not viable: no known conversion from 'A' to 'std::nullptr_t' (aka 'nullptr_t') for 1st argument
    basic_ostream& operator<<(nullptr_t)
                   ^
1 error generated.

CodePudding user response:

You have provided operator<< for a wrong type there. You gave for the std::unordered_map not for the my_namespace::A. Hence, the compiler can not find a operator<< for my_namespace::A.

You need instead

namespace my_namespace
{
    // ...

    std::ostream& operator<<(std::ostream& os, A const& a) noexcept
    //                                        ^^^^^^^^^^^^
    {
        for (auto const& [k, v] : a.map)
            os << " " << k << ": " << v;
        return os;
    }
}

See demo

CodePudding user response:

You overload operator<< for std::unordered_map<int, std::string> but not my_namespace::A here.

One way is to overload it for my_namespace::A.

std::ostream& operator<<(std::ostream& os, const A& a) noexcept
{
    for (auto const& [k, v] : a.map)
        os << " " << k << ": " << v;
    return os;
}

Another way is to make A can be implicitly converted to std::unordered_map<int, std::string>.

struct A
{
    A() {}
    std::unordered_map<int, std::string> map{{1, "hello"}, {2, "goodbye"}};
    operator std::unordered_map<int, std::string>() const {
        return map;
    }
};
  • Related