Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function is ambiguous, which is not

Tags:

c++

templates

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?

like image 690
Viaduct Avatar asked Jun 09 '18 23:06

Viaduct


People also ask

What is ambiguous function C++?

You cannot override one virtual function with two or more ambiguous virtual functions. This can happen in a derived class that inherits from two nonvirtual bases that are derived from a virtual base class.

How do you fix an ambiguous call to overloaded function?

There are two ways to resolve this ambiguity: Typecast char to float. Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.

What is ambiguity in function overloading?

When the compiler is unable to decide which function it should invoke first among the overloaded functions, this situation is known as function overloading ambiguity. The compiler does not run the program if it shows ambiguity error.


1 Answers

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.

like image 82
MSalters Avatar answered Nov 15 '22 10:11

MSalters