C++ function overload priority [duplicate] - c++

This question already has answers here:
Unexpected overload resolution in visual studio involving void*, string and const char[]
(3 answers)
Closed 7 years ago.
Why would the code give an output: bool ?
Is there any way I could make the const char* to match the string version?
#include <string>
#include <iostream>
void func(bool)
{
std::cout << "bool" << std::endl;
}
void func(const std::string&)
{
std::cout << "string" << std::endl;
}
int main(int argc, char* argv[])
{
func("hello");
}

This happens because the compiler will prefer built-in conversions to user-defined conversions. The conversion from a pointer to a bool is built-in, so that overload is selected rather than constructing a std::string.
You could add an overload which takes a const char* and forwards it to the std::string version:
void func(const char* arg)
{
func(std::string{arg});
}

To answer the why:
Function matching is the process by which the compiler selects which function to call among an overload set.
Here, there are two viable candidates (the two functions you defined). To pick one, the compiler ranks the conversion they imply.
The first candidate void func(bool) implies an array-to-pointer conversion followed by a boolean conversion (from const char[6] to const char* to bool)
The second candidate implies a user-defined conversion (calling the std::string ctor taking a const char*)
The second conversion has lower ranking, so the first candidate is selected as the best match.

According to the standard N4431 §13.3.3.2/2 Ranking implicit conversion sequences [over.ics.rank] (emphasis mine):
When comparing the basic forms of implicit conversion sequences (as
defined in 13.3.3.1) (2.1) — 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, and (2.2) — a
user-defined conversion sequence (13.3.3.1.2) is a better conversion
sequence than an ellipsis conversion sequence (13.3.3.1.3).
Consequently, because the char const * to bool is a standard implicit conversion compared to the implicit conversion to std::string which is a user-defined conversion is a better conversion and is preferred in overload resolution.
In order to force overload resolution to choose the std::string version:
func(std::string("hello"));

Related

C++ function match priority [duplicate]

This question already has an answer here:
Why does pointer decay take priority over a deduced template?
(1 answer)
Closed 7 years ago.
I have simple question about the c++ function match priority. Suppose I have such code:
#include <iostream>
void func(const char*)
{
std::cout << "const char*" << std::endl;
}
template<int N>
void func(const char (&) [N])
{
std::cout << "const char (&) [N]" << std::endl;
}
int main(int argc, char* argv[])
{
func("Hello world");
return 0;
}
The result of the code is (with Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn)):
const char*
I think the literal type of the "Hello world" should be const char[]. Why the const char* version has a higher priority than the const char (&)[] version?
Overload resolution attempts to find the best conversion. The following paragraph lists the relevant bullet points that could distinguish both conversions:
Standard conversion sequence S1 is a better conversion sequence than
standard conversion sequence S2 if
S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by 13.3.3.1.1, excluding any
Lvalue Transformation; the identity conversion sequence is considered
to be a subsequence of any non-identity conversion sequence) or, if
not that,
the rank of S1 is better than the rank of S2, or S1 and S2 have the same rank and are distinguishable by the
rules in the paragraph below, or, if not that,
[…]
While the specialization of the function template yields a parameter with an identity conversion, the non-template overload with char const* requires an Array-to-pointer conversion. Intuitively, we'd say that the former is a better match and should thus be selected. However, the array-to-pointer conversion is an Lvalue Transformation, excluded from the first bullet point. And since it has Exact Match Rank, the rank of the conversion isn't different than the rank of the conversion for char const (&)[N], which also has Exact Match Rank. "The rules in the paragraph below" cannot distinguish the conversions either, as they solely address derived-to-base conversions and such, but not array-to-pointer.
In fact, the conversion to char const (&)[N] is not better in any way. But overload resolution discriminates templates:
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
for some argument j, ICSj(F1) is a better conversion
sequence than ICSj(F2), or, if not that,
[…]
F1
is not a function template specialization and F2 is a function
template specialization, or, if not that,
Hence the non-template overload is selected.
In your particular case the relevant part of the resolution rules applied is that non-template functions have precedence over template functions, that's why you see a pointer and not an array reference.

Why no ambiguity in this function call?

I'm wondering why there's no ambiguity in this function call:
#include <iostream>
#include <vector>
template <class T>
class C
{
public:
typedef char c;
typedef double d;
int fun() {}
static c testFun( decltype(&C::fun) ) {return c();}
static d testFun(...) { return d(); }
};
int main() {
C<int>::testFun(0); // Why no ambiguity?
}
http://coliru.stacked-crooked.com/a/241ce5ab82b4a018
There's a ranking of implicit conversion sequences, as defined in [over.ics.rank], emphasis mine:
When comparing the basic forms of implicit conversion sequences...
- 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, and
- a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion
sequence (13.3.3.1.3).
So we have two functions:
static char testFun( int (C::*)() ) { return char(); }
static double testFun( ... ) { return double(); }
Both functions are viable for testFun(0). The first would involve a "null member pointer conversion" as per [conv.mem], and is a standard conversion sequence. The second would match the ellipsis and be an ellipsis conversion sequence. By [over.ics.rank], the former is preferred. There's no ambiguity, the one is strictly better than the other.
An ambiguous overload would arise if we had two equivalent conversion sequences that the compiler could not decide between. Consider if we had something like:
static char testFun(int* ) { return 0; }
static int testFun(char* ) { return 0; }
testFun(0);
Now both overloads would be equivalent as far as the conversion sequences go, so we'd have two viable candidates.
You have a standard conversion vs an ellipsis conversion. The standard says that a standard conversion is a better conversion sequence than the latter. [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
A pointer-to-member conversion is a standard conversion sequence. 0 is a null pointer constant and can be converted to a pointer-to-member. [conv.mem]/p1:
A null pointer constant (4.10) can be converted to a pointer to member type; the result is the null member
pointer value of that type and is distinguishable from any pointer to member not created from a null pointer
constant. Such a conversion is called a null member pointer conversion.
Therefore the first overload is preferred.
13.3.2 Viable functions
A candidate function having fewer than m parameters is viable only if it has an ellipsis in its parameter list (8.3.5). For the purposes of overload resolution, any argument for which there is no corresponding parameter is considered to “match the ellipsis” (13.3.3.1.3).
And also
Viable functions
Given the set of candidate functions, constructed as described above, the next step of overload resolution is examining arguments and parameters to reduce the set to the set of viable functions
To be included in the set of viable functions, the candidate function must satisfy the following:
1) If there are M arguments, the candidate function that has exactly M parameters is viable
2) If the candidate function has less than M parameters, but has an ellipsis parameter, it is viable.
[...]
Overloading resolution
A null pointer literal 0 should be an exact match to a function accepting a function pointer and treated as stronger than matching anything (...).

What overloaded C++ function will be called? [duplicate]

This question already has answers here:
wrong function being picked
(3 answers)
Closed 9 years ago.
Here is the subject of the topic:
#include <string>
#include <iostream>
void test(bool val)
{
std::cout << "bool" << std::endl;
}
void test(std::string val)
{
std::cout << "std::string" << std::endl;
}
int main(int argc, char *argv[])
{
test("hello");
return 0;
}
The output of the program is bool. Why the bool variant selected?
To call the bool overload requires the following conversion:
const char[6] ---> const char* ---> bool
To call the std::string overload requires the following conversion:
const char[6] ---> const char* ---> std::string
This involves a user-defined conversion (using the conversion constructor of std::string). Any conversion sequence without a user-defined conversion is preferred over a sequence with a user-defined conversion.
When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1):
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, and
[...]
A standard conversion sequence is one involving only standard conversions. A user-defined conversion sequence is one involving a single user-defined conversion.
That is because "hello" has type const char[6], which decays to const char*, which in turn can be converted into bool by means of another standard conversion. Therefore, the overall conversion:
const char[6] -> bool
Can be performed just by means of standard conversions.
On the other hand, converting a const char* to an std::string would require a user-defined conversion (invoking the converting constructor of std::string), and standard conversions are preferable over user-defined conversions when doing overload resolution.

Precedence of overloaded cast operators

In the code below, I would expect to get a compiler error if more than one cast operator is defined because of the ambiguity.
#include <iostream>
#include <sstream>
struct A
{
operator const char*() { return "hello world\n"; }
operator float() { return 123.0F; }
//operator int() { return 49; }
};
int main()
{
A a;
std::stringstream ss;
ss << a;
std::cout << ss.str();
return 0;
}
Instead, as long as only one numeric cast operator is defined then it compiles with no errors, no warnings, and the numeric cast is used in preference to the operator const char *(). The order of the declared operators makes no difference.
However if operator int() and operator float() are both defined then I get what I expected from the start:
'operator <<' is ambiguous
Are there precedence rules for casts, or why does the compiler choose the numeric cast by default? I do understand that I should explicitly state which cast I mean, but my question is on the default choice the compiler makes.
Edit: Using compiler MSVC 2010
Conversions are ranked according to § 13.3.3.1 of the C++ Standard. In particular, user-defined conversion sequences pertinent to your example are regulated by § 13.3.3.1.2/1:
"A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion (12.3) followed by a second standard conversion sequence. [...] If the user-defined conversion is specified by a conversion function (12.3.2), the initial standard conversion sequence converts the source type to the implicit object parameter of the conversion function."
All conversions sequences here involve:
a fictitious conversion to the source type of the implicit object parameter of the conversion function;
a user-defined conversion;
an identity conversion to the input type of operator <<.
These conversion sequences all have the same rank. Thus, the call should be ambiguous. If it is not, for me it is a compiler bug.

Why does a quoted string match bool method signature before a std::string?

Given the following methods:
// Method 1
void add(const std::string& header, bool replace);
//Method 2
void add(const std::string& name, const std::string& value);
It would appear that the following code will end up calling method 1 instead of method 2:
something.add("Hello", "World");
I ended up creating another method that looks like this:
//Method 3
void MyClass::add(const char* name, const char* value) {
add(std::string(name), std::string(value));
}
It worked. So it would seem that when a method accepts a "quoted string" it will match in the following order:
const char*
bool
std::string
Why would a quoted string be treated as a bool before a std::string? Is this the usual behavior? I have written a decent amount of code for this project and haven't had any other issues with the wrong method signature being selected...
My guess is the conversion from pointer to bool is an implicit primitive type conversion, where the conversion to std::string requires the call of a constructor and the construction of a temporary.
In your case you have has overloaded functions. Overloading resolution occurs according to Section 13.3.
C++03 13.3.3.2/2:
When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)
— 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, and
— a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).
Conversion pointer into bool is a standard conversion. Conversion pointer into std::string is a user-defined conversion.
4.12 Boolean conversions
An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.
Pointers have an implicit conversion to bool. Perhaps you have seen the following:
void myFunc(int* a)
{
if (a)
++(*a);
}
Now, in C++, implicit conversions between built-in types take precedence over conversions between class-types. So for example, if you had a class:
class Int
{
public:
Int(int i) {}
}
And you overloaded a function for long and Int:
void test(long n) {cout << "long";}
void test(Int n) {cout << "Int";}
You'll see that the following code calls the long overload:
int i;
test(i);