Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is overload resolution is ambiguous in this case?

Tags:

c++

sfinae

I've written this code to check if a class type have begin function.

struct foo //a simple type to check
{
    int begin(){ return 0;}
};

struct Fallback
{
    int begin(){ return 0;}
};

template<typename T>
struct HasfuncBegin : T,Fallback
{
    typedef char one;
    typedef int two;

    template<typename X>
    static one check(int (X::*)() = &HasfuncBegin<T>::begin);
    template<typename X>
    static two check(...);

    enum :bool {yes = sizeof(check<T>())==1, no= !yes};
};

int main()
{
    std::cout<< HasfuncBegin<foo>::yes;
    return 0;
}

Which produces error :

error: call of overloaded 'check()' is ambiguous
     enum {yes = sizeof(check<T>())==1, no= !yes};
                                ^
C:\XXX\main.cpp:24:16: note: candidate: static HasfuncBegin<T>::one HasfuncBegin<T>::check(int (X::*)()) [with X = foo; T = foo; HasfuncBegin<T>::one = char]
     static one check(int (X::*)() = &HasfuncBegin<T>::begin);
                ^
C:\XXX\main.cpp:26:16: note: candidate: static HasfuncBegin<T>::two HasfuncBegin<T>::check(...) [with X = foo; T = foo; HasfuncBegin<T>::two = int]
     static two check(...);


        ^

Can anyone please explain why call is ambiguous (even though first check function with signature one check(int (X::*)() = &HasfuncBegin<T>::begin); has default argument to be used) and also how to make my code work?

Edit:

So here is final working code :

struct foo
{
    int begin(){ return 0;}
};

struct Fallback
{
    int begin(){ return 0;}
};

template<typename T, T ptr> struct dummy{};

template<typename T>
struct HasfuncBegin : T,Fallback
{
    typedef char one;
    typedef int two;


    template<typename X>
    static one check(dummy<int (X::*)(),&HasfuncBegin<X>::begin>*);
// even this won't work, so replace above statement with below commented one
// static one check(dummy<decltype(&HasfuncBegin<X>::begin),&HasfuncBegin<X>::begin>*); 
    template<typename X>
    static two check(...);

    enum {yes = sizeof(check<T>(0))==1, no= !yes};
};
like image 521
Angelus Mortis Avatar asked Oct 19 '22 19:10

Angelus Mortis


1 Answers

The reason for the ambiguity is that both (templated) overloads of check() are valid matches for check<T>(). You may think one is more valid than the other but the rules of the language is that they are both equally valid.

A variable argument function (...) is a match for zero or more arguments (i.e. check<T>()). A function with a single argument that has a default value can match check<T>().

Hence the message about ambiguity.

You haven't actually described what you are trying to achieve with this code (particularly the initialisation of the enum), but are somehow expecting we will work out what you are trying to do. The obvious way to get it to compile would be to remove one of the overloads.

But, unless you describe what you are really trying to achieve, nobody can advise you. Reading sites like this does not grant people mindreading powers.

like image 167
Peter Avatar answered Nov 15 '22 12:11

Peter