Deleting overloaded function. C++11. Call of overloaded ... is ambiguous - c++

There is global function (just example):
void func( int i )
{
std::cout << i + 100 << std::endl;
}
I assume that calling this function with char argument does not make any sense so I use delete:
void func(char) = delete;
So I expect that following calls should be possible:
func(1);
func(3.1);
func(true);
And call with char argument should be forbiden:
func('a');
But that is not true. When calling func('a') I get as expected:
error: use of deleted function ‘void func(char)’
But during calling func(2.3) I get:
error: call of overloaded ‘func(double)’ is ambiguous
Why do I get this error? Without deleting function with char arguments double was converted to int and func(int) was called, why now it is forbidden?

When you call
func(2.3)
you pass a double to the function. The list of candidates contains both func(int) and func(char), as overload resolution happens before delete kicks in:
If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected Ref: cppreference.com, see Avishai's answer for precise standard quotes.
Now double can be converted both to char and int, hence the ambiguity.
Without deleting function with char arguments double was converted to int and func(int) was called, why now it is forbidden?
You get an ambiguity error even without deleteing the char version, see live here. Of course if you only define the func(int), then there will be no ambiguity so double will happily be converted to an int.

Any time a non-exact match is passed in for a function parameter, a conversion must be done. When you have two functions, regardless if one is deleted, they still participate in overload resolution. The compiler picks the best match, then either generates a call to it, or fails if the function is inaccessible or deleted.
For overload resolution to work, it makes a set of candidate functions then sees which has the shortest conversion path to the set of parameters. As far as the rules go, all builtin numeric types are an "equal" conversion. Therefore, if you call with 2.5, which is a double, it must convert and can convert equally to a char OR to an int, with the same ranking, so the call is ambiguous.

It is still ambiguous, as the compiler tries to resolve the overload before checking for deleted functions. See:
§8.4.3 Deleted definitions
A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed.
[
Note:
This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member
to the function. It applies even for references in expressions that are not potentially-evaluated. If a function
is overloaded, it is referenced only if the function is selected by overload resolution.
— end note
]
§13.3.3.1 Implicit conversion sequences:
Implicit conversion sequences are concerned only with the type, cv-qualification, and value category of
the argument and how these are converted to match the corresponding properties of the parameter. Other
properties, such as the lifetime, storage class, alignment, accessibility of the argument, whether the argument
is a bit-field, and whether a function is deleted (8.4.3), are ignored. So, although an implicit conversion
sequence can be defined for a given argument-parameter pair, the conversion from the argument to the
parameter might still be ill-formed in the final analysis.

Related

Does an implicit conversion from function pointer to function exist?

I am primarily making this post to clarify some confusing/misleading information about function pointers that I stumbled upon on Stackoverflow.
Let's begin with an example:
#include <iostream>
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;
void (&fref)()=func;
func();//call through function
(&func)();//call through function pointer
(*fp)();//call through function
fp();//call through function pointer
fref();//call through function
(&fref)();//call through function pointer
}
This prints:
func here
func here
func here
func here
func here
func here
As can be seen a function can be used in place of a function pointer most of the time thanks to function to function pointer decay cppreference.
An lvalue of function type T can be implicitly converted to a prvalue pointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.
But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.
Furthermore this Stackoverflow answer
Note also that you do not need to use the unary * to make the call via the function pointer; both (*p1_foo)(); and (p1_foo)(); have the same result, again because of the function-to-function-pointer conversion.
and this Stackoverflow answer
There's a dual convenience as well: a function pointer in call position is automatically converted to a function value, so you don't have to write * to call through a function pointer.
Make it seem like there exists an implicit function pointer to function conversion.
No
An implicit conversion from function pointer to function doesn't exist.
As of ISO International Standard ISO/IEC 14882:2020(E) – Programming Language C++ there are no mentions of such a conversion.
But apart from that it looks a function pointer can also be used in place of a function as I can use it to call a function without explicitly derefencing.
This is probably why some SO answers (and even some less known C++ books!) come to the incorrect conclusion that a function pointer is essentially the same as a function and use the function to function pointer decay as evidence. However this implicit conversion only works in one way! Meaning that the quoted section of the first SO answer is incorrect.
Why does the function call succeed anyway?
The reason as to why we can call a function using a function pointer without explicit derefernce actually lies in the way the built in function call operator "()" works cppreference:
The expression that names the function can be
a) lvalue expression that refers to a function
b) pointer to function
c) explicit class member access expression that selects a member function
d) implicit class member access expression, e.g. member function name used within another member function.
Aha! So the function call operator can directly take a function pointer as expression. There is no implicit conversion. If you read the quote from the second SO answer it explicitly mentions that the function pointer needs to be in call position that is called using the function call operator.
This also means that in all contexts outside of a function call a function pointer does need to be dereferenced where a function is expected such as when initializing a function reference:
void func ()
{
std::cout<<"func here"<<'\n';
}
int main()
{
void (*fp)()=func;//OK (implicit function to function pointer decay)
void (&&fref1)()=&func;//error: invalid initialization of reference of type 'void (&&)()' from expression of type 'void (*)()'
void (&fref2)()=*fp;//OK
void (&fref3)()=fp;// error: invalid initialization of reference of type 'void (&)()' from expression of type 'void (*)()'
}

C++ primer 5 ed. Overloaded Functions and User-Defined Conversion

Hello I am at chapter 14 in C++ primer 5 ed. I've understood anything from previous chapters. It is really a very good book. however when I've reached this, it is a bit ambiguous for me:
"In a call to an overloaded function, if two (or more) user-defined conversions provide a viable match, the conversions are considered equally good. The rank of any standard conversions that might or might not be required is not considered. Whether a built-in conversion is also needed is considered only if the overload set can be
matched using the same conversion function.
For example, our call to manip would be ambiguous even if one of the classes defined a constructor that required a standard conversion for the argument:
struct E {
E(double);
// other members
};
void manip2(const C&);
void manip2(const E&);
// error ambiguous: two different user defined conversions could be used
manip2(10); // manip2(C(10) or
manip2(E(double(10)))
In this case, C has a conversion from int and E has a conversion from double. For the call manip2(10), both manip2 functions are viable:
• manip2(const C&) is viable because C has a converting constructor that takes an int. That constructor is an exact match for the argument.
• manip2(const E&) is viable because E has a converting constructor that takes a double and we can use a standard conversion to convert the int argument in order to use that converting constructor.
Because calls to the overloaded functions require different user-defined conversions from one another, this call is ambiguous. In particular, even though one of the calls requires a standard conversion and the other is an exact match, the compiler will still flag this call as an error.
Note In a call to an overloaded function, the rank of an additional standard conversion (if any) matters only if the viable functions require the same user-defined conversion. If different user-defined conversions are needed, then the call is ambiguous."
Can someone explain the last paragraph with an example? Thank you!

What is "myfunc" vs "myfunc()"

A noob question that probbaly applies to C as well as C++. Let's say I have
void myfunc() {
blah;
}
So, I call this function with:
myfunc();
However, no compiler error is produced when I "call" it with:
myfunc;
Program runs, but myfunc doesn't get called. So, what is C++ interpreting this as?
Now, I'm doing this in the Arduino IDE, all one big lump of code, so I don't get segfaults, etc. So maybe this would throw a runtime error on a dynamically linked host.
myfunc without the parens is the address of the function in memory.
For example, if you have to pass a function to some other function, you would do it with that.
A good example of this is in bsearch in the c standard library, where you need to pass a user defined comparator function in order to do a generic search.
The compiler just evaluates the expression. Since you're evaluating the name of a function, it's basically a no-op.
It's just like this:
int main() {
42; // evaluates 42 but does nothing with it
}
Your compiler should warn you that the result of the expression is unused, anyway.
In C myfunc or any other function name represents the function itself, which will be implicitly converted to a function pointer
Function to pointer
An lvalue of function type T can be implicitly converted to a prvalue pointer to that function. This does not apply to non-static member functions because lvalues that refer to non-static member functions do not exist.
https://en.cppreference.com/w/cpp/language/implicit_conversion#Function_to_pointer
and () is an operator that when applies to a function pointer or a function object will invoke that function
Built-in function call operator
The function call expressions have the form
E ( A1, A2, A3,... )
where
E is an expression that names a function
A1, A2, A3,... is a possibly empty list of arbitrary expressions, except the comma operator is not allowed at the top level to avoid ambiguity.
The expression that names the function can be
lvalue expression that refers to a function
pointer to function
explicit class member access expression that selects a member function
implicit class member access expression, e.g. member function name used within another member function.
So without the function-call operator myfunc; is just a no-op expression that contains a function pointer. If you've turned on compiler warnings (which you should really do) then they'd shout at you about the issue. GCC says that
statement is a reference, not call, to function 'func' [-Waddress]
warning: statement has no effect [-Wunused-value]
while Clang outputs warning: expression result unused [-Wunused-value]

Pointer to member function weirdness

I'm trying to do some binding with my C++ code, and use pointer to member functions.
I have the following code :
class A
{
explicit A(float);
}
class B
{
void setA(A);
void setA(float);
}
Then I declare the pointer to member functions :
(void (B::*)(A))&B::setA
(void (B::*)(float))&B::setA
The compiler (MSVC11) finds the second line is ambiguous.
If I comment setA(A) in class B, both lines are considered ok by the compiler (!)
Is it a compiler bug?
Is there a way to circumvent that, without modifying class B's signature?
EDIT :
Actually, the code I posted was oversimplified from my real classes and did compile..
Here's a modified version that really reproduces the bug :
class A
{
public:
explicit A(float f=1.0f, float g=1.0f) {}
};
class B
{
public:
void setA(A){}
void setA(float f, float g=1.0f){}
};
with
(void (B::*)(A))&B::setA
(void (B::*)(float))&B::setA
(void (B::*)(float,float))&B::setA
The 2nd line brings a compile error :
error C2440: 'type casting' : impossible to convert 'overloaded-function' to 'void (__thiscall B::* )(float)'
I would say this is a bug. Per Paragraph 13.4/1 of the C++11 Standard:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a
pointer to function or a pointer to member function for a specific function from the overload set. [...] . The function selected
is the one whose type is identical to the function type of the target type required in the context. [...] The target can be
— an object or reference being initialized (8.5, 8.5.3),
— the left side of an assignment (5.17),
— a parameter of a function (5.2.2),
— a parameter of a user-defined operator (13.5),
— the return value of a function, operator function, or conversion (6.6.3),
— an explicit type conversion (5.2.3, 5.2.9, 5.4), or
— a non-type template-parameter (14.3.2).
Since it is pretty clear which member function from the overload set has a signature identical to the one you are explicitly casting it to, your code is legal.
Besides, your code compiles fine with Clang 3.2, GCC 4.7.2, GCC 4.8, ICC 13.0.1 and (!) VC10. See, for instance, this live example.
EDIT:
The new code you posted is indeed illegal.
The second cast cannot be resolved, because none of the member functions setA() takes only one float parameter. Therefore, the compiler doesn't know which function you mean by the expression &B::setA. Normally, it would try to disambiguate based on the contextual explicit conversion, but that doesn't help, because it specifies a signature which is incompatible with the signature of both overloads of setA().
If you are wondering why this is the case and why the second overload is not picked, then the reason is that a parameter with a default argument is still a formal parameter of your function (even if it could be omitted in some calls), and its type still counts as part of the function's signature.
Default arguments, on the other hand, are not part of a function's signature:
1.3.20 [defns.signature.member]
signature
<class member function> name, parameter type list (8.3.5), class of which the function is a member, cv-qualifiers (if any), and ref-qualifier (if any)
Now if you remove the overload setA(A), the compiler does know what member function the expression &B::setA refers to, because there is only one. No need to use the explicit cast in order to resolve the expression.
Then, since function pointers can be cast to function pointers of other types, the compiler performs an additional conversion to the specified target type.

Should this compile? Overload resolution and implicit conversions

This example seems to compile with VC10 and gcc (though my version of gcc is very old).
EDIT: R. Martinho Fernandez tried this on gcc 4.7 and the behaviour is still the same.
struct Base
{
operator double() const { return 0.0; }
};
struct foo
{
foo(const char* c) {}
};
struct Something : public Base
{
void operator[](const foo& f) {}
};
int main()
{
Something d;
d["32"];
return 0;
}
But clang complains:
test4.cpp:19:6: error: use of overloaded operator '[]' is ambiguous (with operand types 'Something' and 'const char [3]')
d["32"]
~^~~~~
test4.cpp:13:10: note: candidate function
void operator[](const foo& f) {}
^
test4.cpp:19:6: note: built-in candidate operator[](long, const char *)
d["32"]
^
test4.cpp:19:6: note: built-in candidate operator[](long, const restrict char *)
test4.cpp:19:6: note: built-in candidate operator[](long, const volatile char *)
test4.cpp:19:6: note: built-in candidate operator[](long, const volatile restrict char *)
The overload resolution is considering two possible functions from looking at this expression:
calling Something::operator[] (after a user defined conversion)
calling built in operator for const char* (think "32"[d]) (after a user defined conversion and standard conversion double to long).
If I had written d["32"] as d.operator[]("32"), then overload resolution won't even look at option 2, and clang will also compile fine.
EDIT: (clarification of questions)
This seems to be a complicated area in overload resolution, and because of that I'd appreciate very much answers that explain in detail the overload resolution in this case, and cite the standard (if there's some obscure/advanced likely to be unknown rule).
If clang is correct, I'm also interested in knowing why the two are ambiguous / one is not preferred over another. The answer likely would have to explain how overload resolution considers implicit conversions (both user defined and standard conversions) involved on the two candidates and why one is not better than the other.
Note: if operator double() is changed to operator bool(), all three (clang, vc, gcc) will refuse to compile with similar ambiguous error.
It should be easier to picture why the overload resolution is ambiguous by going through it step-by-step.
§13.5.5 [over.sub]
Thus, a subscripting expression x[y] is interpreted as x.operator[](y) for a class object x of type T if T::operator[](T1) exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3.3).
Now, we first need an overload set. That's constructed according to §13.3.1 and contains member aswell as non-member functions. See this answer of mine for a more detailed explanation.
§13.3.1 [over.match.funcs]
p2 The set of candidate functions can contain both member and non-member functions to be resolved against the same argument list. So that argument and parameter lists are comparable within this heterogeneous set, a member function is considered to have an extra parameter, called the implicit object parameter, which represents the object for which the member function has been called. [...]
p3 Similarly, when appropriate, the context can construct an argument list that contains an implied object argument to denote the object to be operated on.
// abstract overload set (return types omitted since irrelevant)
f1(Something&, foo const&); // linked to Something::operator[](foo const&)
f2(std::ptrdiff_t, char const*); // linked to operator[](std::ptrdiff_t, char const*)
f3(char const*, std::ptrdiff_t); // linked to operator[](char const*, std::ptrdiff_t)
Then, an argument list is constructed:
// abstract argument list
(Something&, char const[3]) // 'Something&' is the implied object argument
And then the argument list is tested against every member of the overload set:
f1 -> identity match on argument 1, conversion required for argument 2
f2 -> conversion required for argument 1, conversion required for argument 2 (decay)
f3 -> argument 1 incompatible, argument 2 incompatible, discarded
Then, since we found out that there are implicit conversions required, we take a look at §13.3.3 [over.match.best] p1:
Define ICSi(F) as follows:
if F is a static member function, [...]; otherwise,
let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.
Now let's construct those implicit conversion sequences for f1 and f2 in the overload set (§13.3.3.1):
ICS1(f1): 'Something&' -> 'Someting&', standard conversion sequence
ICS2(f1): 'char const[3]' -> 'foo const&', user-defined conversion sequence
ICS1(f2): 'Something&' -> 'std::ptrdiff_t', user-defined conversion sequence
ICS2(f2): 'char const[3]' -> 'char const*', standard conversion sequence
§13.3.3.2 [over.ics.rank] p2
a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence.
So ICS1(f1) is better than ICS1(f2) and ICS2(f1) is worse than ICS2(f2).
Conversely, ICS1(f2) is worse than ICS1(f1) and ICS2(f2) is better than ICS2(f1).
§13.3.3 [over.match.best]
p1 (cont.) Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then [...]
p2 If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution; otherwise the call is ill-formed.
Well, f*ck. :) As such, Clang is correct in rejecting that code.
It seems there is no question that both Something::operator[](const foo& f) and the built-in operator[](long, const char *) are viable candidate functions (13.3.2) for overload resolution. The types of real arguments are Something and const char*, and implicit conversion sequences (ICFs) I think are:
for Something::operator[](const foo& f): (1-1) identity conversion, and (1-2) foo("32") through foo::foo(const char*);
for operator[](long, const char *): (2-1) long(double(d)) through Something::operator double() const (inherited from Base), and (2-2) identity conversion.
Now if we rank these ICFs according to (13.3.3.2), we can see that (1-1) is a better conversion than (2-1), and (1-2) is a worse conversion than (2-2). According to the definition in (13.3.3),
a viable function F1 is defined to be a better function than another viable function
F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), ...
Therefore, neither of the considered two candidate functions is better than the other one, and thus the call is ill-formed. I.e. Clang appears to be correct, and the code should not compile.
It would seem from 13.6 in the C++11 spec that clang is correct here:
13.6
Built-in operators
[over.built]
The candidate operator functions that represent the built-in operators defined in Clause 5 are specified in
this subclause. These candidate functions participate in the operator overload resolution process as described
in 13.3.1.2 and are used for no other purpose. [ Note: Because built-in operators take only operands with
non-class type, and operator overload resolution occurs only when an operand expression originally has class
or enumeration type, operator overload resolution can resolve to a built-in operator only when an operand
has a class type that has a user-defined conversion to a non-class type appropriate for the operator, or when
an operand has an enumeration type that can be converted to a type appropriate for the operator. Also note
that some of the candidate operator functions given in this subclause are more permissive than the built-in
operators themselves. As described in 13.3.1.2, after a built-in operator is selected by overload resolution
the expression is subject to the requirements for the built-in operator given in Clause 5, and therefore to
any additional semantic constraints given there. If there is a user-written candidate with the same name
and parameter types as a built-in candidate operator function, the built-in operator function is hidden and
is not included in the set of candidate functions. — end note ]
:
For every cv-qualified or cv-unqualified object type T there exist candidate operator functions of the form
T& operator[](T *, std::ptrdiff_t);
T& operator[](std::ptrdiff_t, T *);
edit
Once you get past which operator functions exist, this just becomes standard overload resolution as described by section 13.3 of the standard -- about 10 pages of details, but the gist of it is that for a function call to not be ambiguous, there needs to be a single function that is at least as good a match as all the possible, viable functions on every argument, and a better match than the others on at least one argument. There's a lot of spec detail on exactly what 'better' means, but it boils down to (in this case) a match not requiring any user-defined conversion operator or object constructor is better than one which does.
So in this case, there are two viable matches:
void Something::operator[](const foo& f)
operator[](long, const char *)
The first is a better match for the first argument, while the second is a better match for the second. So unless there's some other function that is better than both of these, its ambiguous.
That latter point is a possble workaround -- add:
void operator[](const char *a) { return (*this)[foo(a)]; }
to class Something