Why this constructor is being called? - c++

I'm confused about following program about why it calls first constructor.
class A
{
public:
A(const char *c="\0")
{
cout<<"Constructor without arg";
}
A(string c)
{
cout<<"New one";
}
};
int main()
{
A a="AMD";
return 0;
}
Output is
Constructor without arg

"AMD" is a const char[], which is implicitly converted to const char*, so the first constructor [A(const char *c="\0")]is the best match.
Note that A(const char *c="\0") is not a constructor without an argument, it's a constructor which takes a single const char* as an argument, and has an optional default value to use when a const char* isn't specified. In this case, you're passing a const char*, so it uses it.

Because a string literal is of type const char[] which implicitly converts to const char* which is preferred over the user-defined conversion std::string(const char*) (This is not really the signature of the string constructor, but enough for this explanation).
Also: initialization is not assignment. This is why a constructor and not operator= is called in the first place.
The preferred syntax for assignment in C++11 would be A a{"ASDF"};. It makes things more uniform.

You're calling the constructor with a const char * because that is what "AMD" is. It's not a string. If you put A a(string("AMD")) it will work.

Related

use global string as default param with move semantic

i want to reuse a global string, and avoid copy ctor. and usually used as a default param in some function, my code like below.
i avoid to overload constructor because c++ not support constructor called in constructor.
and i know if i use "const char* aaa" instead of using "const std::string aaa",
it will also fine, but copy cannot avoid..
i use variable not macro, because of it's multiline format ugly and code expand reason
so how should be the perfect solution here?
const std::string aaa = R"(a long code string [xxx] )";
class A {
public:
A(const std::string &&a = aaa) { std::cout<< a; }
};
A a;
A aa("bb");
then i will get the error
error: rvalue reference to type 'const basic_string<[3 * ...]>' cannot bind to lvalue of type 'const basic_string<[3 * ...]>'
A(const std::string &&a = aaa) { std::cout<< a; }

implicit constructor not recognized

I'm trying to figure out why the compiler does not deduce that it should use the string constructor of Obj.
Shouldn't implicit construction be enabled for this case? (i pass const reference string and const reference Obj)
Isn't that the entire idea of implicit construction? what am i missing here?
class Obj
{
public:
Obj(const std::string& str)
{
}
void operator+=(const Obj& other)
{
cout << "operator+=" << endl;
}
Obj& operator++()
{
operator +=("something"); // error
return *this;
}
};
i'm compiling with gcc 4.8.2,
thanks!
The conversion from the string literal "something" to Obj would require two user-defined conversions: one from the string literal to an std::string, and one from std::string to Obj using your constructor. Implicit conversion sequences are limited to containing only one user-defined conversion.
The best way to solve this problem is to add another constructor that takes a C string,
Obj(const char* str)
If you don't want to add such a constructor and you want to perform this conversion just once, you could:
Write operator+=(std::string("something")) (perform the first conversion explicitly)
(C++14) Write operator+=("something"s), which uses the new user-defined literal suffix s to construct std::string
You aren't allowed more than one user defined conversion. You have two, char* to std::string, and std::string to Obj. You can fix this by passing an std::string to your operator+=:
Obj& operator++()
{
operator +=(std::string("something"));
return *this;
}
Alternatively, you can add an implicit constructor that takes a const char*"
Obj(const char* str)

Overloaded Bool/String Ambiguity

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/

Function overloading for string reference and const char pointer

Is it legal to define two class functions, one overloaded with a reference to a string and the other overloaded with a const char*?
void funcA(const std::string& s)
void funcA(const char* s)
Can I guarantee that if I call funcA() with a const char* input, it will not call the string function? I'm asking because there is an implicit construction from a const char* to a string.
Yes, it's valid. If you pass a const char*, the second overload is an exact match, which is preferred over all other overloads, particularly ones involving user-defined conversions (such as converting to a const std::string).

C++ const char* overloading confusion

I don't understand why this program produces the output below.
void blah(const char* ) {printf("const char*\n");}
void blah(const std::string&) {printf("const string ref\n");}
template<class t>
void blah(t) {printf ("unknown\n");}
int main(int, char*)
{
blah("hi");
char a[4];
blah(a);
std::string s;
blah(s);
getch();
}
Outputs:
const char*
unknown
const string
In VS2008. It is willing to convert the std::string to a const reference, but why won't it convert the char* to a const char* and use the overload?
The type of "hi" is const char[3], whereas the type of a is char[4].
So, the first call requires only array-to-pointer conversion (aka "decay"). The third call requires only binding an object to a reference-to-const (I don't think "converting" is the correct terminology for reference-binding, although I may be mistaken). The second call would require array decay and a pointer conversion in order to call the const char* overload.
I claim without actually checking the overload resolution text in the standard that this extra step is what makes the template a better match than the const char* overload.
Btw, if you change "unknown\n" to "%s\n", typeid(t).name() then you can see what the type t was deduced as. For your code, it is deduced as char* (because arrays can't be passed by value), but see what happens if you change the template to take a t& parameter instead of t. Then t can be deduced as char[4].