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?
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.
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.
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.
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.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With