#include <string>
#include <iostream>
#include <vector>
class HasPtrValue {
public:
HasPtrValue(const HasPtrValue& h): ps(new std::string(*h.ps)) { std::cout << "copy" << std::endl;}
HasPtrValue(const std::string &s = std::string()): ps(new std::string(s)) { std::cout << "string/default" << std::endl;}
~HasPtrValue() { delete ps; }
private:
std::string *ps;
};
using namespace std;
int main(){
string s = "stackoverflow";
vector<HasPtrValue> a(5, s);
}
The above code compiles fine outputting:
string/default
copy
copy
copy
copy
copy
This suggests to me the vector first directly initialises a temporary HasPtrValue object using the string object (doing HasPtrValue(s))and then copy-constructs the 5 elements from this temporary. How come, then, the following code does not compile:
int main(){
vector<HasPtrValue> a(5, "stackoverflow");
}
If it was directly initialising the HasPtrValue (doing HasPtrValue("stackoverflow")) then there would be no issue in the const string& constructor taking up the role of creating the temporary. I get the error;
error: no matching function for call to 'std::vector<HasPtrValue>::vector(int, const char [14])'|
I thought I'd try it with a simpler class that uses an int constructor and converts from a double:
class A{
public:
A(const int& a): x(a) { }
int x = 2;
};
int main(){
vector<A> a(5, 5.5);
}
Except this compiles fine. What part of the vector implementation prevents using a const char* conversion in the constructor?
Because it needs two user defined conversions, const char* -> std::string, and then std::string -> HasPtrValue, but only once user defined implicit conversion is permitted in an implicit conversion sequence.
13.3.3.1.2$1 User-defined conversion sequences [over.ics.user]
A user-defined conversion sequence consists of an initial standard
conversion sequence followed by a userdefined conversion (12.3)
followed by a second standard conversion sequence.
Note here only one level of user defined implicit conversion is legal. For your case this must be handled by explicit conversions; So you can:
vector<HasPtrValue> a(5, std::string("stackoverflow"));
int main(){
vector<HasPtrValue> a(5, string("stackoverflow"));
}
Your constructor requires std::string and "stackoverflow" is char array.
Alternatively you can define additional constructor accepting char[].
Related
class A {
int x;
std::string s;
public:
A(std::string _s): x(0), s(_s) {
std::cout << "\tA(string)\n" ;
}
A(int _x): x(_x), s("") {
std::cout << "\tA(int)\n" ;
}
A(const A &other): x(other.x), s(other.s) {
std::cout << "\tA(A& other)\n" ;
}
};
int main() {
std::string str = "Hello";
A obj_1(str);
A obj_2 = str;
A obj_3(10);
A obj_4 = 10;
char ch = 'a';
A obj_5 = ch; // How is this working?
// A obj_6 = "Hello"; // And not this?
const char *ptr = "Hello";
// A obj_7 = ptr; // or this?
return 0;
}
On executing this code, the output is:
A(string)
A(string)
A(int)
A(int)
A(int)
As far as I understand, obj_1 and obj_3 are created directly by using the respective ctors. For obj_2 and obj_4, the compiler does an implicit conversion by calling their respective ctor (so only 1 implicit conversion is required in each case). However, for obj_5 the compiler first has to convert from char to int and then one more implicit conversion to call the int-ctor. But C++ standard allows only 1 implicit conversion. So what is happening here?
Also, in that case "Hello" should first get converted to a std::string then one more implicit conversion to call the string-ctor. But this doesn't work.
But C++ standard allows only 1 implicit conversion.
Thats not correct.
From cppreference:
Implicit conversion sequence consists of the following, in this order:
zero or one standard conversion sequence;
zero or one user-defined conversion;
zero or one standard conversion sequence.
From the language point of view, const char[N] -> std::string (or const char* to std::string) is a user-defined conversion. Hence, the commented out lines are errors. On the other hand,
A obj_5 = ch; // How is this working?
is fine, because there is only a single user-defined conversion involved.
I'm attempting to copy-initialize my CObj class as follows in the main() function:
#include <string>
#include <iostream>
class CObj
{
public:
CObj(std::string const& str) : m_str(str) { std::cout << "constructor" << std::endl; }
~CObj() { std::cout << "destructor" << std::endl; }
private:
std::string m_str;
};
int main()
{
CObj obj = "hello";
std::cout << "done" << std::endl;
}
However, the line CObj obj = "hello" fails to compile even though std::string is implicitly constructible from a char const*. According to my understanding here, this should work. Any reason why it doesn't? If I do this it works:
CObj obj = std::string("hello");
The literal "Hello" has type const char[6] : in order to call your constructor, two conversions are required : one to std::string and a second one to CObj .
But C++ only allows one user-defined conversion when doing an implicit conversion :
C++ Standard section ยง 12.3/4 [class.conv]
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
[...]
At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.
This is why this works :
CObj obj = std::string("hello");
Or this:
CObj obj("hello");
Or you could provide a constructor that accepts a const char* :
CObj(const char* cstr) : m_str(cstr) { ... }
I would always advise to make such constructors explicit to avoid unwanted implicit conversions, unless it really brings something to the user of the class.
You are limited to at most one user-defined conversion when instantiating an object (i.e. char[6] -> std::string and std::string -> CObj is one conversion too many).
To fix:
int main()
{
using namespace std::literals::string_literals; // this is necessary
// for the literal conversion
CObj obj = "hello"s; // note the extra "s", (which constructs a std::string)
std::cout << "done" << std::endl;
}
I want to cast a custom class to a string which compiles in VS2005 very well. But in VS2012 I get the compiler error error C2440: 'type cast' : cannot convert from 'A' to 'std::string'. What do I have to change? This is my example:
#include <string>
using namespace std;
class A
{
public:
A& operator=(const char* c);
operator string ();
operator const char* ();
private:
string value;
};
A::operator string () { return string((const char*)(*this)); }
A& A::operator = (const char* aValue) { value = aValue; return *this; }
A::operator const char *() { const char* wort = "Hello"; return wort; }
int main()
{
A a;
string s = (string)a; // C2440
}
The problem is that there are two possible explicit conversions from A to string - via the conversion operator to string; or via the conversion operator to const char *, then via the conversion constructor to string.
Simply making the conversion implicit will resolve the ambiguity; the second conversion requires two user-defined conversions, and so cannot be chosen for an implicit conversion:
string s = a;
However, the class is still a bit flaky, since sometimes you might need an explicit conversion. I would consider removing at least one of the implicit conversion operators - perhaps replace them with explicit operators (if your compiler supports such things), or with named functions (like string itself does with c_str()).
The conversion is ambiguous.
Stay away from C style casts, and prefer to make the conversions explicit.
#include <string>
using namespace std;
class A
{
public:
A& operator=(const char* c);
explicit operator string ();
explicit operator const char* ();
private:
string value;
};
A::operator string () { return string(static_cast<const char*>(*this)); }
A& A::operator = (const char* aValue) { value = aValue; return *this; }
A::operator const char *() { const char* wort = "Hello"; return wort; }
int main()
{
A a;
string s = static_cast<std::string>(a);
}
Your two conversion operators step on each others toes. Each of them works for implicit conversions. But an explicit cast is like a direct constructor call. In your code
string s = (string)a;
is equivalent to
string s = static_cast<string>(a);
which transforms to something like
string tmp(a);
string s(std::move(tmp)); // this move can be elided
// lifetime of tmp ends here
The crux is the direct initialization string tmp(a). There are two viable string constructors: string(const string&) and explicit string(const char *) and your two conversions allow calling either. As neither conversion sequence is better, the call is ambiguous.
By the way, the version using copy initialization without explicit cast is not ambiguous:
string s = a;
should work. Depending on that is very brittle, so not recommended.
You should make your conversion operators explicit (if you are using C++11) or drop one of them.
Consider the following code.
#include <iostream>
using namespace std;
class Test
{
private:
int x,y;
public:
Test () {
cout <<" Inside Constructor "<<endl;
x=100;
}
explicit Test (const Test & t)
{
cout <<"Inside Copy Constructor "<<endl;
x = t.x;
}
void display()
{
cout <<" X is "<<x<<endl;
}
};
int main (int argc, char ** argv){
Test t;
t.display();
cout <<"--- Using Copy constructor "<<endl;
Test t2(t);
t2.display ();
Test t3=t2;
t3.display ();
}
Test (const Test & t) -> is a copy constructor
Question:
Is the same used as a "Conversion Operator" ?
Test t3 = t2 [ Here copy Constructor is treated as a conversion operator]
I am not sure if my understanding is correct?. Kindly correct me if i am wrong?
Test t3=t2;
Should never compile, if copy c-tor is explicit.
n3337 12.3.1/3
A non-explicit copy/move constructor (12.8) is a converting constructor. An implicitly-declared copy/move
constructor is not an explicit constructor; it may be called for implicit type conversions.
This quote appears to following question: Implicit copy constructor
So, in your case, it's not conversion constructor.
In C++, the term conversion implies two different types : source type and destination type.
Copy-constructor, by definition, involves only one type : source type and destination type are same. So it cannot be called a conversion function.
when you use T t3 = t2. It will call the assignment operator which you haven't define it.
I thought that constructors control initialization and operator= functions control assignment in C++. So why does this code work?
#include <iostream>
#include <cmath>
using namespace std;
class Deg {
public:
Deg() {}
Deg(int a) : d(a) {}
void operator()(double a)
{
cout << pow(a,d) << endl;
}
private:
int d;
};
int
main(int argc, char **argv)
{
Deg d = 2;
d(5);
d = 3; /* this shouldn't work, Deg doesn't have an operator= that takes an int */
d(5);
return 0;
}
On the third line of the main function, I am assigning an int to an object of class Deg. Since I don't have an operator=(int) function, I thought that this would certainly fail...but instead it calls the Deg(int a) constructor. So do constructors control assignment as well?
This is what's called implicit type conversion. The compiler will look to see if there's a constructor to directly change from the type you're assigning to the type you're trying to assign, and call it. You can stop it from happening by adding the explicit keyword in front of the constructor you wouldn't like to be implicitly called, like this:
explicit Deg(int a) : d(a) {}
Just to clarify JonM's answer:
For the line d = 3, an assignment operator is involved. 3 is being implicitly converted to a Deg, as JonM said, and then that Deg is assigned to d using the compiler-generated assignment operator (which by default does a member-wise assignment). If you want to prevent assignment, you must declare a private assignment operator (and do not implement it):
//...
private:
Deg& operator=(const Deg&);
}