Can't pass lvalue to construct an rvalue [duplicate] - c++

This question already has answers here:
Which part of the C++ standard allow to declare variable in parenthesis?
(2 answers)
Closed 2 years ago.
Is there anyone who can help explain why UseString in my following example cannot accept an lvalue as a parameter? I know a temporary String is created in my case, but I cannot explain why it has to accept an rvalue here.
#include <utility>
using namespace std;
struct String
{
String(const char* cstr)
{
}
};
struct UseString
{
UseString(const String& str)
{
}
};
int main()
{
const char* cstr = "abc";
UseString(std::move(cstr)); //Correct
UseString("abc"); // Correct
UseString(cstr); // Error but why UseString cannot accept lvalue as parameter in this case?
return 0;
}

The problem is because UseString(cstr); does not do what you think it does.
It is actually a variable declaration, not a constructor call. It is treated exactly the same as UseString cstr; And cstr was already declared earlier, hence the error.
See Which part of the C++ standard allow to declare variable in parenthesis?
Per this Live Demo:
prog.cpp: In function ‘int main()’:
prog.cpp:24:16: error: conflicting declaration ‘UseString cstr’
UseString(cstr);
^
prog.cpp:21:14: note: previous declaration as ‘const char* cstr’
const char* cstr = "abc";
^~~~
There is no way the compiler can confuse UseString(std::move(cstr)); and UseString("abc"); as variable declarations, so they are treated as calls to the constructor instead.
To solve this, you can use curly braces instead of parenthesis:
UseString{std::move(cstr)};
UseString{"abc"};
UseString{cstr};
Live Demo

Related

compiler reports const instead of const& [duplicate]

This question already has answers here:
Does each expression in C++ have a non-reference type
(5 answers)
Is Expression type same as object, references, or functions type?
(2 answers)
Closed 4 months ago.
Tried to compile following code, can't understand error message.
#include<iostream>
#include<string>
using namespace std;
struct S {
string a{"abc"};
const string& data() { return a; }
};
int main() {
S s;
int a = s.data(); // error: no viable conversion from 'const std::string' to 'int'
return 0;
}
Question: why does compiler say 'const std::string' instead of 'const std::string&'?
Tried with Apple clang 14.0.0 and g++ 12, same error message.
data() returns a reference to a const std::string object, yes. But, you are not converting the reference itself to an int, you are converting the std::string object that it refers to.
A reference is just an alias, once a reference has been bound to an object, any access of the reference is really accessing the object instead.
That is why the error message does not include &.
Expressions (such as s.data()) never have reference types.
& is silently removed from the type, and, in case of a function call, dictates the value category of the resulting expression (lvalue in this case).

C++ lambda capture by value semantic? [duplicate]

This question already has answers here:
C++0x lambda capture by value always const?
(2 answers)
Closed 1 year ago.
class TestGetStr {
public:
string a;
string getString() {
return a;
}
};
void acceptConstString(const string & a) {
std::cout << a << std::endl;
}
int main(int argc, const char * argv[]) {
auto testGetStr = TestGetStr();
acceptConstString(testGetStr.getString()); //compile ok
auto testaaa = [testGetStr](){
//compile error 'this' argument to member function 'getString' has type 'const TestGetStr', but function is not marked const
acceptConstString(testGetStr.getString());
};
Difference between normal call and lambda capture?
The normal call can compile, but the lambda call can't compile.
And Why? Thanks for more detail.
You can add mutable qualifier.
auto testaaa = [testGetStr]() mutable {
// ^^^^^^^
acceptConstString(testGetStr.getString());
};
Otherwise the operator() of the lambda is const-qualified, and then can't call non-const member functions on the captured object.
mutable: allows body to modify the objects captured by copy, and to call their non-const member functions
Unless the keyword mutable was used in the lambda-expression, the
function-call operator is const-qualified and the objects that were
captured by copy are non-modifiable from inside this operator().
PS: Or better to make TestGetStr::getString() const member function.

What do parameterless constructors mean when explicitly called at declaration [duplicate]

This question already has answers here:
Default constructor with empty brackets
(9 answers)
Closed 8 years ago.
The question sounds a bit odd, but check the code sample
#include <iostream>
using namespace std;
int main() {
string a, b(), c("test");
// No problems
a = c;
// tester.cpp:9:7: error: assignment of function ‘std::string b()’
b = c;
// tester.cpp:10:7: error: invalid conversion from ‘std::string (*)() {aka std::basic_string<char> (*)()}’ to ‘char’
a = b;
// No problems
c = a;
}
You can see that it looks like b is created with the default constructor, but in fact it is not. So my question is really is, what does string b() mean?
Condensing your code to string b();, what you're doing here is declaring a prototype to a function called b that returns a string and takes no arguments.
The commas in the "compound declaration" are obfuscating this.
It's actually a function declaration. It's possible to declare local functions but not to define them. So therefore it's not possible to explicitly call the default constructor.
Classic mistake, but the error message already says it: function std::string b() /.

C++ function overload resolution - bool vs string [duplicate]

This question already has an answer here:
String-bool comparsion - why?
(1 answer)
Closed 8 years ago.
I've found some unexpected behavior using the VC++2010 compiler with function overloading:
struct A {
A();
void O(const bool in); //(1)
void O(const std::string in);//(2)
}
Some of the following calls do not resolve like I would think:
A a;
a.O(true);//calls (1)
a.O("what?");//calls (1)
a.O(std::string("better..."));//calls (2)
Can someone explain to me why the second call resolves to the boolean function and what the motivation behind resolving in that way is?
The type of "what?" is char const[6], which after decaying to char const* while being passed into the function, is implicitly convertible to bool. The standard conversion takes precedence over user-defined implicit conversions, like the case of converting char const* to std::string.

Why this is not a vexing parse?

Basically this is a follow up of this question about most vexing parse. I can understand that this is due to the ambiguity between the function declaration and variable definition.
But in Comeau online, I just tired the following.
class T{
public:
T(int i){
}
int fun1(){
return 1;
}
};
int main()
{
T myT(10); // I thought it'd be a function declaration that takes an int and returns a type T
myT.fun1(); // and a compiler error out here.
}
But it compiles fine and there were no errors. I looked into the standard docs but couldn't come to a reasoning.
So, what am I missing here?
Because 10 is not a type. :)
This would be a Most Vexing Parse:
T myT(T());
// T() gets interpreted as function pointer argument to a function returning T();
// This is equivalent to:
T myT(T (*fn)());
Another variety of the Most Vexing Parse is this one:
unsigned char c = 42;
T myT(int(c));
// int(c) gets interpreted as an int argument called c.
// This is equivalent to:
T myT(int c);
The 10 cannot be a parameter type name, so this must be a variable declaration.
The compiler must choose a function declaration when it can do that, but in many cases like this it cannot and there is no ambiguity.
It's not a vexing parse because you used an integer literal rather than, say:
T myT(T());
As in this complete example:
#include <iostream>
struct T { int f() { return 1; } };
int main(int argc, char** argv) {
T t(T());
std::cout << t.f() << '\n';
return 0;
}
Which is ambiguous because it could mean:
myT is a T initialised with a default-constructed T; or
myT is a function returning a T and taking one argument of type T(), which denotes a zero-argument function whose return type is also T.
The latter interpretation is the default one, which is why a compiler error results from attempting to use the newly declared function as though it were the object you expected it to be.
See the Wikipedia article about it.