Overloaded Bool/String Ambiguity - c++

Why is C++ casting the string literal I pass in as a bool rather than a string?
#include <iostream>
using namespace std;
class A
{
public:
A(string v)
{
cout << v;
}
A(bool v)
{
cout << v;
}
};
int main()
{
A("hello");
return 0;
}
Output: 1
Is it because the compiler isn't smart enough to make the jump from char * to string and rather just assumes that bool is the closest thing to a pointer? Is my only option to make an explicit char * constructor that basically does the exact same thing as the string constructor?

If you have C++11 you can use a delegating constructor:
A(char const* s) : A(std::string(s)) { }
The reason the boolean converting-constructor is chosen over the one for std::string is because the conversion from char const* to bool is a standard conversion while the one to std::string is a user-defined conversion. Standard conversions have a greater rank than user-defined conversions.

With
A(string("hello"));
it will give the expected result.
Why is it so ?
It's because of the standard conversions:
"hello" is understood as a const char* pointer
this pointer can be converted to a bool (section 4.12 of the standard: "A prvalue of (...) pointer (...) type can be converted to a prvalue of type bool." )
the conversion from "hello" to string is not considered because section 12.3 of standard explains that "Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions" and "User-defined conversions are applied only where they are unambiguous". Wouldn't you have the bool constructor the std::string conversion would be done implicitely.
How to get what you expected ?
Just add the missing constructor for string litterals:
A(const char* v)
{
cout << v; // or convert v to string if you want to store it in a string member
}
Of course, instead of rewriting a constructor from scratch, you could opt for a delegate as suggested by 0x499602D2 in another answer.

Recently I passed this problem too, let me share another way.
You can change the bool constructor to a unsigned char. So the decay and implict conversion of string literal don't happen, and the std::string constructor takes place.
class A
{
public:
A(string v)
{
cout << v;
}
A(unsigned char v)
{
cout << static_cast<bool>(v);
}
};
int main()
{
A("Hello"); // <- Call A(string)
A(false); // <- Call A(unsigned char)
}
This way you don't need to provide always overloads to std::string and const char* neither making code bloat constructing the std::string at the client call site.
I don't claim that's better, but it's simpler.

When selecting an overloaded method this is the order that the compiler tries:
Exact match
Promotion
Standard numerical conversion
User defined operators
A pointer doesn't promote to bool but it does convert to bool. A char* uses an std operator to convert to std::string. Note that if char* used the same number in this list to convert to both bool and std::string it would be ambiguous which method the compiler should choose, so the compiler would throw an "ambiguous overload" error.
I would throw my weight behind 0x499602D2's solution. If you have C++11 your best bet is to call: A(char* s) : A(std::string(s)){}
If you don't have C++11 then I would create an A(char* s) constructor and abstract the logic of the A(std::string) constructor into a method and call that method from both constructors.
http://www.learncpp.com/cpp-tutorial/76-function-overloading/

Related

Why does the copy constructor automatically cast my data into a different type?

I can't figure out a decent title - please edit it if you have a better description. Hopefully someone can help me understand what is going on. I have the following code, I just compiled on linux - it works. I just don't understand how when I call Foo with a const char*, that it gets cast by (the compiler?) into my object Test.
#include <iostream>
#include <cstring>
class Test
{
public:
Test(const char* _data = "")
{
int length = strlen(_data);
internalData = new char[length+1];
strncpy(internalData, _data, length);
internalData[length] = '\0';
}
char* internalData;
};
class Bar
{
public:
void Foo(Test _data)
{
std::cout << "Data: " << _data.internalData << std::endl;
}
};
int main(int argc, char* argv[])
{
Bar b;
b.Foo("This is my data");
}
// Output: Data: This is my data
So, I'm curious as to why/how this works - is it the compiler? runtime? Is there documentation as to why - that someone could provide a link to?
The compiler has to look for a valid conversion from char const* to Test, so it searches for constructors from Test to convert the argument. This is standard behavior allowed by §12.3/1 (emphasis mine):
Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).
The implicit conversion sequence creates a temporary instance of Test which is then copied or moved to the parameter. This copy/move can actually be elided by the compiler by an optimization known as copy-elision.
If you want to prevent implicit conversions, you can mark your constructor explicit:
explicit Test(char const* = "");

why does it call bool_function first?

I am curious about the following code, somebody could explain why does it call bool func first ? isn`t "str" more suitable for arg type string ?
void a(bool input)
{
cout<<"I amd first"<<endl;
cout<<input<<endl;
}
void a(const string &input)
{
cout<<"I amd second"<<endl;
cout<<input<<endl;
}
int main( )
{
a("str"); // call void a(bool input)
a(string("str")); //call void a(const string &input)
return 0;
}
"str" is of type const char[4], which decays immediately to const char *, and the conversion from any pointer type to bool is considered before non-explicit constructors to custom types.
So, I'd say that the answer is "because the standard says so".
The relevant passage should be 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 [...]
I'd guess it is because when you call a("str"), you're trying to call a function with parameters const char *. It will convert any type of pointer to bool before any other implicit conversion (::std::string etc).

Ambiguous string::operator= call for type with implicit conversion to int and string

Given the following program:
#include <iostream>
#include <string>
using namespace std;
struct GenericType{
operator string(){
return "Hello World";
}
operator int(){
return 111;
}
operator double(){
return 123.4;
}
};
int main(){
int i = GenericType();
string s = GenericType();
double d = GenericType();
cout << i << s << d << endl;
i = GenericType();
s = GenericType(); //This is the troublesome line
d = GenericType();
cout << i << s << d << endl;
}
It compiles on Visual Studio 11, but not clang or gcc. It is having trouble because it wants to implicitly convert from a GenericType to an int to a char but it also could return a string and so there is an ambiguity (operator=(char) and operator=(string) both match GenericType).
The copy constructor is just fine, however.
My question is: How do I resolve this ambiguity without modifying the contents of main? What do I need to do to modify GenericType to handle this situation?
I believe that gcc and clang are correct.
There are two operator= overloads in play:
string& operator=(string const& str); // (1)
string& operator=(char ch); // (2)
Both of these operator= overloads require a user-defined conversion from your argument of type GenericType. (1) requires the use of the conversion to string. (2) requires the use of the conversion to int, followed by a standard conversion to char.
The important thing is that both overloads require a user-defined conversion. To determine whether one of these conversions is better than the other, we can look to the overload resolution rules, specifically the following rule from C++11 §13.3.3.2/3 (reformatted for clarity):
User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if
they contain the same user-defined conversion function or constructor or aggregate initialization and
the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2.
Note that an and joins the two parts of the rule, so both parts must be satisfied. The first part of the rule is not satisfied: the two user-defined conversion sequences use different user-defined conversion functions.
Therefore, neither conversion is better, and the call is ambiguous.
[I don't have a good suggestion on how to fix the problem without changing the definition of main(). Implicit conversions are usually not a good idea; they are sometimes very useful, but more frequently they are likely to cause overload ambiguities or other weird overloading behavior.]
There was a gcc bug report in which this problem was described, and resolved as by design: compiler incorrectly diagnoses ambigous operator overload.
I believe GCC is wrong. In the book "The C++ Programming Language" by Bjarne Stroustrup, there is a whole chapter devoted to operator overloading. In the section 11.4.1, the first paragraph says this:
"An assignment of a value of type V to an object of class X is legal if there is an assignment operator X::operator=(Z) so that V is Z or there is a unique conversion of V to Z. Initialization is treated equivalently."
In your example, GCC accepts "string s = GenericType();" yet rejects "s = GenericType();", so it is obviously not treating the assignment the same way as the initialization. That was my first clue something is amiss in GCC.
GCC reports 3 candidates for conversion of GenericType to string in the assignment, all in basic_string.h. One is the correct conversion, one it reports is not valid, and the third causes the ambiguity. This is the operator overload in basic_string.h that causes the ambiguity:
/**
* #brief Set value to string of length 1.
* #param c Source character.
*
* Assigning to a character makes this string length 1 and
* (*this)[0] == #a c.
*/
basic_string& operator=(_CharT __c) {
this->assign(1, __c);
return *this;
}
This isn't a valid conversion because it accepts an operand that doesn't match the type of object that is passed to it. In no place is as assignment to a char attempted, therefore this conversion shouldn't be a candidate at all much less one that causes ambiguity. GCC appears to be mixing up the template type with the operand type in its member.
EDIT: I wasn't aware that assigning an integer to a string was in fact legal, as an integer can be converted to a char, which can be assigned to a string (although a string can't be initialized to a char!). GenericType defines a conversion to an int, thus making this member a valid candidate. However, I still maintain this is not a valid conversion, the reason being that using this conversion would result in two user defined implicit conversions for the assignment, first from GenericType to int, then from int to string. As stated in the same book 11.4.1, "only one level of user-defined implicit conversion is legal."
My question is: How do I resolve this ambiguity without modifying the contents of main?
Create your own class named string that doesn't have an ambiguous operator= and then don't using the std one.
Obviously this isn't a very good solution, but it works and main doesn't have to change.
I don't think you can get the behavior you want any other way.
This solution works
#include <iostream>
#include <string>
#include <type_traits>
using namespace std;
struct GenericType{
operator string(){
return "Hello World";
}
template <typename T, typename = std::enable_if_t <
std::is_same<T, double>::value ||
std::is_same<T, int>::value>>
operator T(){
return 123.4;
}
};
int main(){
int i = GenericType();
string s = GenericType();
double d = GenericType();
cout << i << s << d << endl;
i = GenericType();
s = GenericType();
d = GenericType();
cout << i << s << d << endl;
}
And a more general solution. I think you don't need to create operators for each arithmetic type, since implicit conversions will do the trick.
// ...
template <typename T, typename = std::enable_if_t
<std::is_arithmetic<T>::value && !std::is_same<T, char>::value>>
operator T() const
{
return std::stod("123.4");
}
//...

are casts overridable operations? if so, how?

Is it possible to override (C-style) casts in C++?
Suppose I have the code
double x = 42;
int k = (int)x;
Can I make the cast in the second line execute some code I wrote? Something like
// I don't know C++
// I have no idea if this has more syntax errors than words
operator (int)(double) {
std::cout << "casting from double to int" << std::endl;
}
The reason I ask is because of the question "Is there any way to get gcc or clang to warn on explicit casts?" and my suggestion there.
§ 12.3.1/1 "Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9)."
Yes, we can make conversions, but only if one or both sides is a user-defined type, so we can't make one for double to int.
struct demostruct {
demostruct(int x) :data(x) {} //used for conversions from int to demostruct
operator int() {return data;} //used for conversions from demostruct to int
int data;
};
int main(int argc, char** argv) {
demostruct ds = argc; //conversion from int to demostruct
return ds; //conversion from demostruct to int
}
As Robᵩ pointed out, you can add the explicit keyword to either of those conversion functions, which requires the user to explicitly cast them with a (demostruct)argc or (int)ds like in your code, instead of having them implicitly convert. If you convert to and from the same type, it's usually best to have one or both as explicit, otherwise you might get compilation errors.
Yes, but only for your own types. Look at this:
#include <iostream>
struct D {
// "explicit" keyword requires C++11
explicit operator int() { std::cout << __FUNCTION__ << "\n"; }
};
int main () {
int i;
D d;
//i = d;
i = (int)d;
}
So, you cannot create double::operator int(), but you could create MyDouble::operator int().
You can’t overload operators for built-in types, but you can write a conversion operator for a user-defined type:
struct Double {
double value;
operator int() const {
shenanigans();
return value;
}
};
Since your question arose from a need to find explicit casts in code, also be aware that C++ has explicit casting operators. These are not only clearer than C-style casts, but also eminently searchable:
static_cast<T>(x) // Cast based on static type conversion.
dynamic_cast<T>(x) // Cast based on runtime type information.
const_cast<T>(x) // Add or remove const or volatile qualification.
reinterpret_cast<T>(x) // Cast between unrelated pointer and integral types.
Conversions to other types are overloadable operators in C++ (some examples here), but this fact will not help you.
Stroustrup wanted the language to be extensible, but not mutable. Therefore, overloading an operator only extends the operations to new types, but you cannot redefine what happens with any old types.
"However, to avoid absurdities, it is (still) not allowed to provide new meanings for the built-in operators for built-in types. Thus, the language remains extensible but not mutable."

Why is there an implicit type conversion from pointers to bool in C++?

Consider the class foo with two constructors defined like this:
class foo
{
public:
foo(const std::string& filename) {std::cout << "ctor 1" << std::endl;}
foo(const bool some_flag = false) {std::cout << "ctor 2" << std::endl;}
};
Instantiate the class with a string literal, and guess which constructor is called?
foo a ("/path/to/file");
Output:
ctor 2
I don't know about you, but I don't find that the most intuitive behavior in programming history. I bet there is some clever reason for it, though, and I'd like to know what that might be?
It's very common in C to write this
void f(T* ptr) {
if (ptr) {
// ptr is not NULL
}
}
You should make a const char* constructor.
You're passing a char* to the foo constructor. This can be implicitly converted to a boolean (as can all pointers) or to a std::string. From the compiler's point of view, the first conversion is "closer" than the second because it favours standard conversions (i.e. pointer to bool) over user provided conversions (the std::string(char*) constructor).
You're confusing two issues. One is that "blah" can be implicitly converted to a string and the other is that const char* can be implicitly converted into a boolean. It's very logical to see the compiler go to the implicit conversion which minimizes the total amount of conversions necessary.