Skip to content

Clang fails to build due to operator<< ambiguities #442

@davidchappelle

Description

@davidchappelle

I am trying to build latest msgpack and found that simple custom adaptors are not compiling using clang however they do compile using gcc. In particular I am seeing compilation errors such as these:

main.cpp:53:16: error: use of overloaded operator '<<' is ambiguous (with operand types 'msgpack::object::with_zone' and 'const std::string' (aka 'const basic_string<char>'))
        object << f.name();
        ~~~~~~ ^  ~~~~~~~~
/home/dchappelle/environment/staging/include/msgpack/v1/adaptor/adaptor_base.hpp:71:6: note: candidate function [with T = std::basic_string<char>]
void operator<< (msgpack::object::with_zone& o, T const& v) {
     ^
/home/dchappelle/environment/staging/include/msgpack/v2/adaptor/adaptor_base.hpp:66:6: note: candidate function [with T = std::basic_string<char>]
void operator<< (msgpack::object::with_zone& o, T const& v) {
     ^
/home/dchappelle/environment/staging/include/msgpack/v1/adaptor/adaptor_base.hpp:65:6: note: candidate function [with T = std::basic_string<char>]
void operator<< (msgpack::object& o, T const& v) {
     ^
/home/dchappelle/environment/staging/include/msgpack/v2/adaptor/adaptor_base.hpp:60:6: note: candidate function [with T = std::basic_string<char>]
void operator<< (msgpack::object& o, T const& v) {
     ^
1 error generated.

Here is a simple program that reproduces the issue:

#include <iostream>
#include <string>
#include <msgpack.hpp>

class foo
{
public:
    foo() {}
    ~foo() {}

    const std::string& name() const { return m_name; }
    void set_name(const std::string& name) { m_name = name; }
private:
    std::string m_name;
};

namespace msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {

template<>
struct convert<foo>
{
    msgpack::object const& operator()(
            msgpack::object const& object,
            foo& f) const
    {
        f.set_name(object.as<std::string>());
        return object;
    }
};

template<>
struct pack<foo>
{
    template <typename Stream>
    msgpack::packer<Stream>& operator()(
            msgpack::packer<Stream>& packer,
            foo const& f) const
    {
        packer.pack(f.name());
        return packer;
    }
};

template <>
struct object_with_zone<foo>
{
    void operator()(
            msgpack::object::with_zone& object,
            const foo& f) const
    {
        object << f.name();
    }
};

} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack

int main(int argc, char** argv)
{
    foo f;
    msgpack::zone zone;
    msgpack::object object(f, zone);
    return 0;
}

If I use MSGPACK_API_VERSION_NAMESPACE(v1) then it compiles. So this is likely an issue with the inlining of the namespaces. I also went back through the commit history to find which commit introduced this problem since it was compiling before without issue until I updated msgpack. I found that the issue was introduced by this commit:

commit 54cb4350b3838e76b3fe117b0d1d5c75cdeb8da8
Author: Takatoshi Kondo <[email protected]>
Date:   Fri Jan 22 21:44:58 2016 +0900

    Re-organized tree to prepare for version 2.0.0.

    See https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_versioning

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions