I have a class like this one:
class Test{
public:
Test(string value);
Test(bool value);
};
If I create an object like this:
Test test("Just a test...");
The bool constructor is called!
Anyone knows why?
Thanks
The type of "Just a test..." is const char *, which can be implicitly converted to either bool or std::string. Because std::string isn't a built in type, the const char *s is converted to a bool. You can prevent that by explicitly converting the const char * to a std::string:
Test test(std::string("Just a test..."));
This is a well known C++ annoyance.
Your string literal has type of chat const[]. You've got two constructors, conversion sequences from char const[] to Test look like this:
1) char const[] -> char const* -> bool
2) char const[] -> char const* -> std::string
1) is a built-in standard conversion whereas 2) is a user-defined conversion. Built-in conversions have precedence over user defined conversions, thus your string literal gets converted more easily to bool than to std::string.
The type of "Just a test..." is const char*. There is a built-in conversion from pointers to bool which is preferred over the non-built-in conversion from const char* to std::string.
The reason that the bool conversion is preferred is because std::string, while part of the standard library, is not a built-in type like integers, pointers, and booleans. It acts like any other class, and so its conversion constructors are considered only after conversions to built-in types.
One way to circumvent this problem, is to provide another constructor taking a const char* and then converting explicitly to a std::string.
When you have a constructor (especially multiple constructors) that take only a single argument, it may be suitable to declare them "explicit" to avoid these kind of surprises. This forces the user of the class to make sure he gives the correct type to the constructor he wishes to use and prevents these implicit type conversions from being done behind the users back and hiding hard to find bugs.
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=15&rll=1
In C++0x, this has been extended to conversion operators to prevent the same issue
http://www2.research.att.com/~bs/C++0xFAQ.html#explicit-convertion
One way is to create a variable of type std::string and pass the variable in:
std::string test = "TEST";
A a(test);
This way the type is explicitly defined as std::string it won't default to the constructor that accepts bool
Related
I've recently ran into a very pesky problem working with C++03.
I needed to create a new string class that expands on the abilities of std::string, providing additional methods and more convenient handling.
All was going well except for one issue: If some function expected a MyString parameter and was given a string literal (i.e. "Hello") it couldn't do the conversion from const char[6] into MyString, despite the fact that MyString has a c'tor that accepts std::string.
For example, these lines will work:
MyString mStr("Hello");
MyString mStr = "Hello";
But this code will not work:
void myFunc(const MyString& mStr);
myFunc("Hello");
Because "no constructor exists that can perform the conversion from const char[6] into MyString".
Adding a c'tor that accepts const char * didn't help solve the problem, and even trying to mark them with explicit in different combinations didn't help at all.
After spending quite a few hours on this error, I got to the conclusion that it might not be possible to do such a thing because it may require two implicit conversions which the compiler will not perform, however as I said, adding a c'tor from const char * to enable conversion in 1 step didn't change anything. So before I'm giving up on this, do any of you have any ideas if it's even possible to solve this problem?
As for MyString's constructor taking std::string const&, the compiler can not convert from const char* through std::string to MyString, in order to call myFunc, because that's two implicit conversions, while it can do only one. See this post.
In case of const char* being the parameter, I could not reproduce your erorrs. In addition, making a constructor explicit will do no good here, it will ban even that one implicit conversion that was allowed. See it here.
Defining constructor with parameter "const char *"(MyString(const char *)) should resolve this issue.
I have something like this...
void f(dclass b);
class dclass
{
dclass(string s);
};
f("s");
This does not seem to work. In principle, it could with double conversion: char* -> string -> dclass
So there is no such a thing in C++. Or maybe some compilers support it... Do you know a language where it may be possible?
It could, but this won't really work in languages with overloading. You turn an O(N) overload resolution into an O(N*M) overload resolution. In general, overloading is considered a more valuable language feature than multiple user-defined conversions.
There can be more than one conversions in one chain, but at most one user-defined conversion can be in the chain. In this case, both const char* -> std::string and std::string -> dclass are user-defined conversions. To solve your issue, you will need to add an implicit constructor that takes a const char*. Of course if you've considered all the undesired effects of implicit constructors.
class dclass
{
dclass(string s);
dclass(const char* ps);
};
For completeness, you can call your function like so:
f(dclass("s"));
I'm currently porting a C++ application to a slightly restricted environment. The application uses the STL, string and stream classes. I'm rewriting simplified versions of these that will play nicely in my environment.
What I'm concerned about is that my application is compiling even without all the necessary operator definitions. For example, for my string classes I defined:
string operator+ (const string& lhs, const string& rhs);
and this was enough. However, I noticed there were often cases that had mystring + "some constant string" and this isn't defined in my code anywhere. When I explicitly added it it was used:
string operator+ (const string& lhs, const char* rhs);
What was going on before that? It compiled successfully before I added the second function. Surely the compiler wouldn't be able to infer how to concatenate c-style strings to my string class.
I'm getting strange behaviour in my program now and I'm wondering if it's due to other operators left undefined. Is there any way to enforce the compiler to require such operator definitions if it's needed by the program?
P.S. My string class is in a unique namespace and unrelated to std::
It's impossible to be certain without seeing the rest of your code, but in this case it's probably not too hard to guess either. You almost certainly have a constructor for your string that takes a char const * as its parameter, so what's happening is that the compiler is using that ctor to convert the char const * to a string, then using string operator+ (const string& lhs, const string& rhs); to concatenate that.
Allowing this to happen is one of (if not the) primary reason for overloading these operators with globals instead of member functions. As member functions they can convert the right operand, but not the left.
When you passed a const char*, a string object was probably constructed and passed to operator+. If you step through the code in a debugger you will probably be able to verify the constructor is being called.
You probably, have a constructor in your class which takes const char * as an input parameter, Most likely this constructor is used for implicit coversions and the weird behavior you see.
Declare your constructor which takes const char * as explicit, this would disable its use for implicit conversions where you do not intend it to be used.
Does your 'string' class have a one argument constructor that takes a const char*? Is that single argument constructor marked as 'explicit'?
If it is not explicit, the the most likely answer is that the compiler is constructing a temporary string object from the char* via your converting constructor, and then using that temporary string to call your two argument addition operator.
The compiler can't know how to convert your string to a std::string or char* unless you specify how.
Look for conversion constructors or cast operators in your class declaration.
class MyString
{
MyString(char*);
MyString(std::string);
operator std::string ();
operator char*();
};
These will be called implicitly.
You can specify the explicit keyword for your constructor to prevent this from happening.
If this doesn't solve the problem, you must have the operators overloaded somewhere, best find them stepping through the code with a debugger.
In C++ is it possible to define conversion operators which are not class members? I know how to do that for regular operators (such as +), but not for conversion operators.
Here is my use case: I work with a C Library which hands me out a PA_Unichar *, where the library defines PA_Unichar to be a 16-bit int. It is actually a string coded in UTF-16. I want to convert it to a std::string coded in UTF-8. I have all the conversion code ready and working, and I am only missing the syntactic sugar that would allow me to write:
PA_Unichar *libOutput = theLibraryFunction();
std::string myString = libOutput;
(usually in one line without the temp variable).
Also worth noting:
I know that std::string doesn't define implicit conversion from char* and I know why. The same reason might apply here, but that's beside the point.
I do have a ustring, subclass of std::string that defines the right conversion operator from PA_Unichar*. It works but this means using ustring variables instead of std::string and that then requires conversion to std::string when I use those strings with other libraries. So that doesn't help very much.
Using an assignment operator doesn't work as those must be class members.
So is it possible to define implicit conversion operators between two types you don't control (in my case PA_Unichar* and std::string), which may or may not be class types?
If not what could be workarounds?
What's wrong with a free function?
std::string convert(PA_Unichar *libOutput);
std::string myString = convert(theLibraryFunction());
Edit answering to the comment:
As DrPizza says: Everybody else is trying to plug the holes opened up by implicit conversions through replacing them with those explicit conversion which you call "visual clutter".
As to the temporary string: Just wait for the next compiler version. It's likely to come with rvalue references and its std::string implementation will implement move semantics on top of that, which eliminates the copy. I have yet to see a cheaper way to speedup your code than than by simply upgrading to a new compiler version.
I don't think you can define "global" conversion operators. The standards say that conversion functions are special member functions. I would propse the following if I could consider the following syntax sugar:
struct mystring : public string
{
mystring(PA_Unichar * utf16_string)
{
// All string functionality is present in your mystring.
// All what you have to do is to write the conversion process.
string::operator=("Hello World!");
string::push_back('!');
// any string operation...
}
};
Be aware that polymorphic behavior of this class is broken. As long as you don't create an object of it through a pointer of type string* though, you are in the safe-side! So, this code is perfect:
mystring str(....);
As said before, the following code is broken!
string* str = new mystring(....);
....
delete str; // only deleting "string", but not "mystring" part of the object
// std::string doesn't define virtual destructor
Implicit conversions are the devil, anyway. Make it explicit with a converting function call.
No, you can't. What you could do as an alternative is to create a conversion constructor in the target class (not your case, as you want to convert to std::string - unless you derive it). But I agree to the other answers, I think an implicit conversion is not recommended in this case - especially because you're not converting from an object but from a pointer. Better to have a free function, your code will be easier to understand and the next programmer to inherit the code will for sure thank you.
std::string provides const char* c_str ( ) const which:
Get C string equivalent
Generates a null-terminated sequence
of characters (c-string) with the same
content as the string object and
returns it as a pointer to an array of
characters.
A terminating null character is
automatically appended.
The returned array points to an
internal location with the required
storage space for this sequence of
characters plus its terminating
null-character, but the values in this
array should not be modified in the
program and are only granted to remain
unchanged until the next call to a
non-constant member function of the
string object.
Why don't they just define operator const char*() const {return c_str();}?
From the C++ Programming Language 20.3.7 (emphasis mine):
Conversion to a C-style string could have been provided by an operator const char*() rather than c_str(). This would have provided the convenience of an implicit conversion at the cost of surprises in cases in which such a conversion was unexpected.
I see at least two problems with the implicit conversion:
Even the explicit conversion that c_str() provides is dangerous enough as is. I've seen a lot of cases where the pointer was stored to be used after the lifetime of the original string object had ended (or the object was modified thus invalidating the pointer). With the explicit call to c_str() you hopefully are aware of these issues. But with the implicit conversion it would be very easy to cause undefined behavior as in:
const char *filename = string("/tmp/") + name;
ofstream tmpfile(filename); // UB
The conversion would also happen in some cases where you wouldn't expect it and the semantics are surprising to say the least:
string name;
if (name) // always true
;
name-2; // pointer arithmetic + UB
These could be avoided by some means but why get into this trouble in the first place?
Because implicit conversions almost never behave as you expect. They can give surprising results in overload resolution, so it's usually better to provide an explicit conversion as std::string does.
The Josuttis book says the following:
This is for safety reasons to prevent unintended type conversions that result in strange behavior (type char * often has strange behavior) and ambiguities (for example, in an expression that combines a string and a C-string it would be possible to convert string into char * and vice versa).
I addition to the rationale provided in the specification (unexpected surprises), if you're mixing C API calls with std::string, you really need to get into the habit of using the ::c_str() method. If you ever call a varargs function (eg: printf, or equivalent) which requires a const char*, and you pass a std::string directly (without calling the extraction method), you won't get a compile error (no type checking for varargs functions), but you will get a runtime error (class layout is not binary identical to a const char*).
Incidentally, CString (in MFC) takes the opposite approach: it has an implicit cast, and the class layout is binary-compatible with const char* (or const w_char*, if compiling for wide character strings, ie: "Unicode").
That's probably because this conversion would have surprising and peculiar semantics. Particularly, the fourth paragraph you quote.
Another reason is that there is an implicit conversion const char* -> string, and this would be just the converse, which would mean strange behavior wrt overload resolution (you shouldn't make both implicit conversions A->B and B->A).
Because C-style strings are a source of bugs and many security problems it's way better to make the conversion explicitly.