Reputation: 16711
Let us consider following example:
#include <type_traits>
#if 1
struct X {};
struct O
{
O(X) { ; }
};
#else
struct O {};
struct X
{
operator O () { return {}; }
};
#endif
static_assert(std::is_convertible< X, O >::value);
struct S
{
void f(X) const { ; }
void f(O) { ; }
};
#include <cstdlib>
int
main()
{
S s;
s.f(X{});
return EXIT_SUCCESS;
}
It gives an error:
error: call to member function 'f' is ambiguous
When I removing const
-qualifier, then the error cease to exist. Equally the same happens, if I add const
-qualifier to the second overloading of f
. I.e. if both overloadings are equally const
-qualified, then all is OK.
Why is it so?
My compiler is clang 3.8.
Upvotes: 5
Views: 187
Reputation: 310980
Member functions have implicit parameter this
.
So to call one of the functions f
the compiler needs either to convert this
to type const S *
or to convert X
to O
.
Neither conversion regarding all parameters is better. So the compiler issues an error.
Upvotes: 2
Reputation: 852
Mark B & Vlad from Moscow answer why, I just reply how can you call them.
you should add explicit
to avoid compiler implicit conversion
#include <iostream>
struct X {};
struct O
{
explicit O(X) { ; }
O() = default;
O(O const &) = default;
O(O &&) = default;
};
struct S
{
void f(X) const { ; }
void f(O) { ; }
};
#include <cstdlib>
int main()
{
S s;
s.f(X{});
return EXIT_SUCCESS;
}
EDIT
if your type O
is in 3party lib
you can add a template to do this.
#include <iostream>
using namespace std;
struct X {};
struct O {
O(X) {
;
}
O() = default;
O(O const&) = default;
O(O&&) = default;
};
struct S {
void f(const X) const {
cout << "X" << endl;
}
void f(O) {
cout << "O" << endl;
}
};
#include <cstdlib>
template<typename TA, typename TB>
void myCall(TA a, TB b) {
((const TA &&)a).f(b);
}
template<>
void myCall(S a, O b) {
a.f(b);
}
template<>
void myCall(S a, X b) {
((const S)a).f(b);
}
int main() {
S s;
myCall(s, X());
//s.f(X());
return EXIT_SUCCESS;
}
Upvotes: 1
Reputation: 96241
Why is it so?
: The reason here is because the const-ness of the s
object itself is also considered in overload resolution. Since s
is non-const it would require adding const to the implicit this
pointer to call the const f
. Calling the non-const f
is an exact match for the this
pointer but requires an implicit conversion from X
to O
via O's converting constructor.
Upvotes: 2