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.
Related
#include <cstdint>
#include <iostream>
struct a_struct {
int64_t* le_int;
bool not_ok;
a_struct() : le_int{ new int64_t(0) }, not_ok{ false } {}
~a_struct() { delete le_int; }
operator bool() const {
return !not_ok;
}
operator int64_t* () {
return le_int;
}
};
int main(int argc, char** argv) {
a_struct s;
s.not_ok = true;
if (!s)//<-
std::cout << "o no." << std::endl;
else if (s.not_ok)
std::cout << "waddu heck?" << std::endl;
return 0;
}
In this example the !s resolution prefers the int64_t*() operator over the const bool() operator.
Why?
This is the "initialization by conversion function" case for overload resolution: http://eel.is/c++draft/over.match.conv
Both conversion functions are candidates because both are non-explicit and their return types are implicitly convertible to bool. Overload resolution is then performed with the object expression s as the argument, and the implied object parameter of the conversion functions as the parameters. The implied object parameter has type T cv &, where T is the class.
Binding T& to T is better than binding T const& to T. This is one of the rules by which implicit conversion sequences are ranked. http://eel.is/c++draft/over.ics.rank#3.2.6
Note that there is a tie-breaker rule involving the return types of the conversion functions. Such tie-breaker rules are only considered after ranking of implicit conversion sequences for each parameter fails to yield a best viable function on account of the fact that every parameter's implicit conversion sequence is neither better nor worse than the implicit conversion sequence for the corresponding parameter of the other function. Thus, only if both conversion functions have the same cv-qualification (resulting in identical implicit conversion sequences for the implied object parameter), the tie-breaker is reached. http://eel.is/c++draft/over.match.best#general-2.2
Since your object s is not const, it prefers the non-const way of calling the type cast operator. So, removing the const from your bool type cast operator does the trick.
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"));
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.
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.
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);