Viaduct
Viaduct

Reputation: 101

function is ambiguous, which is not

I got xxx is ambiguous when I'm working on my c++ project. Since the whole project to too huge to upload in here, I made simple example which popup the same error message.

#include <string>
#include <memory>

namespace a {

template <typename T, typename Target>
inline std::shared_ptr<T> getShared(Target const& t)
{
    return std::static_pointer_cast<T>(t->shared_from_this());
}

class A : public std::enable_shared_from_this<A>
{
};

}

namespace b {

template <typename T, typename Target>
inline std::shared_ptr<T> getShared(Target const& t)
{
    return std::static_pointer_cast<T>(t->shared_from_this());
}

class A : public std::enable_shared_from_this<A>
{
};

void invoke()
{
    // ERROR OCCURED!!!
    a::A* a;
    getShared<a::A>(a);

    // But this is compiled without any problem :(
    //  A* a;
    //  getShared<A>(a);
}

}

int main(int, char**)
{
    b::invoke();

    return 0;
}

And here's the error message...

clang++ -c -pipe -g -std=gnu++1y -Wall -W -fPIC -DQT_QML_DEBUG -I../untitled -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-clang -o main.o ../untitled/main.cpp
../untitled/main.cpp:34:2: error: call to 'getShared' is ambiguous
        getShared<a::A>(a);
        ^~~~~~~~~~~~~~~
../untitled/main.cpp:7:27: note: candidate function [with T = a::A, Target = a::A *]
inline std::shared_ptr<T> getShared(Target const& t)
                          ^
../untitled/main.cpp:21:27: note: candidate function [with T = a::A, Target = a::A *]
inline std::shared_ptr<T> getShared(Target const& t)

I tried with both gcc 6.3.0 and clang 3.8.1-24, and both compilers gave me the same error.

Could somebody let me know what is wrong in this code?

Upvotes: 8

Views: 330

Answers (1)

MSalters
MSalters

Reputation: 179779

The comments basically answer the question, but let's wrap it all up.

The compiler's first challenge is to parse getShared<a::A>(a);. Now this could be operator< and operator>, but the compiler first looks up getShared and notices it's a template, so the <a::A> is the template argument list.

It's also a function template, so a is a function argument. At this point, something complex happens. Since a has type a::A*, it has an associated namespace . The compiler does a new name lookup of getShared, now that it knows it's a function with an argument and an associated namespace. This second lookup also finds a::getShared. That is also a function template, and it can be instantiated with <a::A>. (SFINAE could exclude it, but the argument is OK).

You now have two instantiations, and overload resolution doesn't resolve their ambiguity.

The name of this second lookup is Argument Dependent Lookup, as mentioned by miradulo.

Upvotes: 7

Related Questions