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; }
Related
I have a function which accepts a std::string&:
void f(std::string& s) { ... }
I have a const char* which should be the input parameter for that function. This works:
const char* s1 = "test";
std::string s2{s};
f(s2);
This doesn't:
const char* s1 = "test";
f({s1});
Why isn't this possible? The funny thing is that CLion IDE is not complaining, but the compiler is:
no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘std::basic_string<char>&’
This has nothing to do with constructing std::string from char const*.
f expects a lvalue to a string, and by creating a temporary instance on the spot, you're providing an rvalue, which cannot be bound to a non-const lvalue reference. f(string{}) is just as invalid.
Your function receives a non const reference and you are passing a temporary object, which requires a copy or a const reference parameter. Two solutions, creating another function to receive the object as a rvalue reference and call the other overload within
void f(string&& s) { f(s); }
to allow temporary objects as parameter, or change your function definition to receive any object but as a constant reference
void f(const std::string& s) { ... }
One option is to change your function to take a string by value, not by reference. Then it will work. In any case, in C++11 sometimes it's preferable to pass by value, not by reference.
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/
The code bellow pertains to question Error seemingly inconsistent behaviour in overloaded operator= used in variable definition that has been answered.
My question arized in the context of trying to define and initialize a reference to a structure using an integer.
So I need instead of writting "S s1=3;" I need to write "S& s1=3;" how am I going to manage it;
struct S{
int a,b;
void operator=(int x){a=x;b=x*x;}
S(){};
S(int x){a=x;b=x*x;}
};
int main(){
S s1;s1=5;
S s2;s2=7;
S s3=9;
S s4;
}
The code of main() should be modifified as follows:
int main(){
//S s0=S{15,20};
S s1;s1=5;
S s2;s2=7;
S s3=9;
S s4;
S& s5;s5=10;
S& s6=10;
}
but compiling I have errors:
main.cpp:16:5: error: ‘s5’ declared as reference but not initialized
main.cpp:17:8: error: invalid initialization of non-const reference of type ‘S&’ from an rvalue of type ‘int’ ( regards s6 ).
First of all, you are not using operator=, rather this is a copy-initialization.
That is, the expression S s1 = 3; uses non-explicit constructor S(int x) and also non-explicit and accessible copy constructor S(const S& x) (hopefully without any additional overhead).
Going further, you can't use S& s1 = 3; not because you cannot assign 3 to reference, but because the right hand side of assignment is an R-VALUE (that is, a temporary). However, you can extend its lifetime using const reference to l-value, as r-values like very much to be bound by const l-value references:
const S& s1 = 3;
This will work as long as S(int x) is not marked as explicit.
Alternatively, (you should not do that at all), you can use r-value reference:
S&& s1 = 3; // implicitly
S&& s2 = S(3); // explicitly
And the error you see trying to compile S& s5;:
main.cpp:16:5: error: ‘s5’ declared as reference but not initialized
tells you that you cannot just create a variable that is a reference (as opposed to pointers), without initializing it.
But if you had a validly initialized reference, then whenever you would use assignment, only then the operator= would be invoked:
S s1(1);
S& s1ref = s1;
S s2(2);
s1ref = s2; // s1.operator=(s2);
This is not possible; a reference must refer to an object. You can do either of the following (using C++98 syntax):
S const &s1 (3); // same as S const &s1 = S(3);
or
S s0(3); S &s1(s0);
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.
I'd like to pass a temporary object(std::string for example) to the constructor of my object:
class MyClass{
public:
MyClass(string a):
a(a)
{
}
string a;
};
int main(int argc, char *argv[]){
MyClass a(string());
cout<<a.a<<endl;
return 0;
}
But I receive this error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:28:11: error: request for member ‘a’ in ‘a’, which is of non-class type ‘MyClass(std::string (*)()) {aka MyClass(std::basic_string<char> (*)())}’
Everything works ok if I pass anything to the constructor of temporary object(for example string("")). Why?
This is an instance of what has been dubbed C++'s most vexing parse. The compiler interprets
MyClass a(string());
as the prototype of a function named a returning a MyClass and taking an unnamed string as a parameter.
You can disambiguate it by putting parenthesis around the call to strings constructor:
MyClass a((string()));
Or, as long as MyClass has an accessible copy constructor:
MyClass a = string();
Update for C++11
You can also disambiguate with the universal initialisation syntax, as long as your class doesn't have a constructor that takes an initializer_list:
MyClass a { string() };
As it has already been pointed out by Seth, that is a problem with the language and how the expression is parsed. Basically when the compiler finds the expression MyClass a(string()) it interprets it as the declaration of a function a that has the signature MyClass (std::string (*)()) (The extra (*) comes from an implicit conversion from function to pointer to function in arguments).
There are different approaches to overcome that syntax in your particular case:
MyClass a(""); // 1
MyClass b = std::string(); // 2
MyClass c(( std::string() )); // 3
The first approach is not to use the T() expression to create the rvalue, but rather a constant literal that will produce the same output. The shortcoming of this approach is that in this particular case you can use a literal, but the same solution cannot be applied to other types (i.e. if you had your own type that only had a default constructor)
The second approach is avoiding direct initialization, as the alternative syntax cannot be parsed as a function declaration. The problem with this approach is that while the result in your particular case is the same, it requires the constructor not to be explicit. (I.e. it would fail if your constructor was declared explicit MyClass( std::string const & )), but it is none
The third approach is adding an extra set of parenthesis around the first argument to the constructor (note that the same problem in parsing would happen with MyClass a(std::string(), std::string())). The problem with this approach (opinion) is that it is ugly, but it is otherwise the most flexible of the three.