compiler reports const instead of const& [duplicate] - c++

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).

Related

Use of const and & in functions C++ [duplicate]

This question already has answers here:
C++ Return value, reference, const reference
(5 answers)
What is a reference variable in C++?
(12 answers)
Closed 1 year ago.
I am trying to understand the useage of 'const' and '&' in the following function declaration. I know that the last 'const' means the function cannot change member variables in the class and that 'const std::string& message' means the variable passed to the function cannot be changed, but I don't understand the meaning of 'const Logger&'. What is the purpose of this first 'const' and why is there an '&' following 'Logger'? Is this function meant to return an address or a pointer?
const Logger& log(const std::string& message) const;
So const Logger& is the return type of log. const means you will not be able to edit the return value at all. The return type Logger& means you'll get a reference to a Logger and not a copy of it.

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

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

Boost Hana iterating over tuple of pairs [duplicate]

This question already has an answer here:
hana::second can't deduce type
(1 answer)
Closed 5 years ago.
I have a template class which accepts a tuple of pairs of a type and an integral constant (some of the types can be repeated so it can't be a hana::map). I'm looking to iterate over the tuple and call a static toString() type method defined for each type. The error I am receiving is:
"error: type 'decltype(hana::first(c))' (aka 'boost::hana::type_impl::_ &') cannot be used prior to '::' because it has no members"
struct A
{
static std::string toString() {return std::string("A");}
};
struct B
{
static std::string toString() {return std::string("B");}
};
using namespace hana::literals;
std::array<std::string,3> ret;
constexpr auto tupleOfPairs = hana::make_tuple(
hana::make_pair(hana::type_c<A>, 0_c),
hana::make_pair(hana::type_c<B>, 0_c),
hana::make_pair(hana::type_c<B>, 5_c));
size_t idx = 0;
hana::for_each(tupleOfPairs, [&](auto c)
{
ret[idx++] = decltype(hana::first(c))::type::toString();
});
I had something very similar working when it was just a tuple (using decltype(c)::type::toString()) but as soon as I made the tuple elements pairs with an integral constant I can't seem to extract the type of the first element of the pair and do the same.
Thanks
TL;DNR: That decltype yields a type "reference to ...", which (it's a reference) obviously has no members. Simple fix: remove the reference with std::remove_reference:
ret[idx++] =
std::remove_reference_t<decltype(hana::first(c))>::type::toString();
This is not about hana. Taking it "out of the loop" we can reduce your case further to
#include <string>
struct A {
static std::string toString() {
return std::string("A");
}
};
template<typename T> T & get_it() {
static T thing;
return thing;
}
int main() {
std::string str = decltype(get_it<A>())::toString();
}
This gives (basically) the same error message as yours:
error: 'decltype(get_it())' (aka 'A &') is not a class, namespace, or enumeration
This is telling us that A & (a reference to A) is not a class (etc.) and can thus not have a (static) member. The same is true when your compiler tells you that:
error: type 'decltype(hana::first(c))' (aka 'boost::hana::type_impl::_ &') cannot be used prior to '::' because it has no members
boost::hana::type_impl::_ & is a reference. Of course it has no members. The referenced class has, so just remove the reference with std::remove_reference.
The fact that the return type of first is reference type is also noted in the documentation, btw (emphasis mine):
Returns the first element of a pair.Note that if the Product actually stores the elements it contains, hana::first is required to return a lvalue reference, a lvalue reference to const or a rvalue reference to the first element, where the type of reference must match that of the pair passed to first. If [.., not applicable here].

Compile Error C2662 [duplicate]

This question already has answers here:
c++ error C2662 cannot convert 'this' pointer from 'const Type' to 'Type &'
(4 answers)
Closed 8 years ago.
I'm trying to pass an object as a reference to a function that accepts the object as a const however the compiler is throwing:
error C2662: 'const int DataPacket::GetData(void)': cannot convert 'this' pointer from 'const DataPacket' to 'DataPacket &'
IntelliSense says:
the object has type qualifiers that are not compatible with the member function
object type is: const DataPacket
I made a test-cast of the code to demonstrate the issue:
#include <iostream>
#include <functional>
class DataPacket
{
int SomeVar;
public:
DataPacket(int InitialData)
{
SomeVar = InitialData;
}
const int GetData()
{
return SomeVar;
}
};
void ProcessPacket(const DataPacket& Packet)
{
std::cout << Packet.GetData() << std::endl;
}
int main()
{
std::function<void(const DataPacket& Packet)> f_Callback;
f_Callback = ProcessPacket;
while (true)
{
f_Callback(DataPacket(10));
}
}
Basically I have a STD function which the user can set to use their own callback function. A lower level class creates objects of type DataPacket when new packets arrive. I then want to pass the object into the callback function as a constant reference so not to copy the entire object and restrict the user from changing the original object.
What's going on here? How can I pass DataPacket into f_Callback as a const reference?
The problem is that in the callback, the DataPacket object Packet is marked as const. That means you can't call non-const function in the object.
This can simply be changed by making the GetData member function const, and no it's not what you have done, you have only made the returned integer const, which makes no sense (because the value will just be copied and loose it's const-ness).
Instead declare the function as
int GetData() const;

error in attaching temporary to a reference to const [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
typedef and containers of const pointers
Why is the code emitting an error?
int main()
{
//test code
typedef int& Ref_to_int;
const Ref_to_int ref = 10;
}
The error is:
error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int’
I read the post on prolonging the lifetime of temporaries which says that temporaries can be bound to references to const. Then why is my code not getting compiled?
Here the type of ref is actually reference to int and not const reference to int. The const qualifier is ignored.
$8.3.2 says
Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef (7.1.3) or of a template type argument (14.3), in which case the cv-qualifiers are ignored.
const Ref_to_int ref; is equivalent to int& const ref; and not const int& ref.
Mixing const with a typedef doesn't work the way you're thinking; see this question for more info. These two lines are equivalent:
const Ref_to_int ref;
int& const ref;
You're looking for:
const int& ref;
One way to fix it is to include it in the typedef itself (although you should probably rename it then):
typedef const int& Ref_to_int;
You can't add additional specifiers to a typedef. It doesn't work like a macro.
Your code is effectively
int& const ref = 10; // error
which isn't valid.