Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting overloaded function is ambiguous

I have an issue where creating a function pointer to an overloaded function results in a compile error on g++ 4.7 and g++ 4.8 but not on g++ 4.4, g++ 4.6 or clang++ 3.2 (and possibly VS2010).

Having googled around a bit to find out whether the issue is with g++ or with my code, I still can't decide. Are the overload resolution rules that apply to function pointer conversion different than those that apply to function calls?

This is a somewhat minimized code that demonstrates the issue:

template < class T >
struct Dummy {
    typedef T value_type;
    value_type value;
};

template < class T >
typename T::value_type f (const T& x) {
    return x.value;
}

template < class T >
T f (Dummy< T > const& x) {
    return x.value + 1;
}

int main (int, char**) {
    Dummy< int > d = { 1 };
    // No ambiguity here
    d.value = f(d);
    // This is ambiguous for *some* compilers
    int (* const f_ptr)(Dummy< int > const&) = f;
    return f_ptr( d );
}

clang++ 3.2, g++ 4.4 and g++ 4.6 compile this with -Wall -pedantic --std=c++98 without warnings.

g++ 4.7 and g++ 4.8 however give the following error message:

test.cc: In function ‘int main(int, char**)’:
test.cc:15:45: error: converting overloaded function ‘f’ to type ‘int (* const)(const struct Dummy<int>&)’ is ambiguous
test.cc:6:18: error: candidates are: typename T::Type f(const T&) [with T = Dummy<int>; typename T::Type = int]
test.cc:9:3: error:                 T f(const Dummy<T>&) [with T = int]

Is this an issue with newer versions of g++ or is my code in fact wrong?

If it is, how would one go about resolving such an ambiguity?

like image 814
user2961413 Avatar asked Nov 06 '13 17:11

user2961413


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.

What are the restrictions on overloaded function?

Restrictions on overloadingAny two functions in a set of overloaded functions must have different argument lists. Overloading functions that have argument lists of the same types, based on return type alone, is an error.

Can overloaded functions have different return types?

The return type of a function has no effect on function overloading, therefore the same function signature with different return type will not be overloaded. Example: if there are two functions: int sum() and float sum(), these two will generate a compile-time error as function overloading is not possible here.

What does it mean when a function is overloaded?

Function overloading is a feature of object-oriented programming where two or more functions can have the same name but different parameters. When a function name is overloaded with different jobs it is called Function Overloading.


1 Answers

Is this an issue with newer versions of g++ or is my code in fact wrong?

I guess this is legal code (but I'm not so sure). To add to the list: it does compile with clang 3.3 and icc 13.1.3.

how would one go about resolving such an ambiguity?

You can use

    int (* const f_ptr)(Dummy< int > const&) = f<int>;

to select the second overload or

    int (* const f_ptr)(Dummy< int > const&) = f<Dummy<int> >;

to select the first one.

If you don't want to manually disambiguate (like my suggestion above) I can suggest a workaround that uses SFINAE to disambiguate. I'm assuming you can use C++11 (default template arguments for function templates) but I believe with some extra work it can be extended to C++98.

Change the definitions of f to:

template < class T, class R = typename T::value_type>
R f (const T&) {
    return x.value;
}

template < class T, class R = T>
R f (Dummy< T > const&) {
    return x.value + 1;
}

With this, the original line (below) compiles fine in gcc (4.7.3 and 4.8.1):

int (* const f_ptr)(Dummy< int > const&) = f;
like image 95
Cassio Neri Avatar answered Oct 02 '22 19:10

Cassio Neri