When I have a member function marked as const and inspect the types of the member variables I get some results I don't expect.
#include <iostream>
#include <string>
template<typename T>
struct type_printer;
class const_type_test {
public:
void test() const {
type_printer<decltype(value)> _;
}
int& test2() const {
return value;
}
void test3() const {
auto& x = value;
type_printer<decltype(x)> _;
}
void test4() const {
auto* x = &value;
type_printer<decltype(*x)> _;
}
private:
int value;
};
int main(int argc, char** argv)
{
const const_type_test x;
return 0;
}
My understanding is that when you are in a const method the method is effectively some name mangled name then they parameter type is classname const* const. I always thought that in the const method scope the member variables are effectively const, i.e. value would be const int. However when using the compiler error to deduce the types I get types I don't expect.
The error output for void const_type_test::test() const
: aggregate type_printer<int> _
has incomplete type and cannot be defined, type_printer<decltype(value)> _;
So I am seeing the type was deduced as int. I thought it would be const int as you can not change the value. Am I using decltype wrong? Or have I a hole in my understanding.
The reason I guess for asking is that in test2
the compiler complains: binding reference of type int&
to const int
discards qualifiers. Which is exactly what I expect. Can bind a const reference to non const reference.
Example 3 shows the following error: error: aggregate type_printer<const int&> _
has incomplete type and cannot be defined type_printer<decltype(x)> _
. Which is what I expect it has been deduced as a const reference.
Example 4: deduces also a type_printer<const int&>
which I thought would be a pointer.
Keen to get some reference to the standard to find out where the holes in my knowledge are. I am also wondering if there are some weird type deduction rules when using decltype
that are tripping me up.
The const member functions are the functions which are declared as constant in the program. The object called by these functions cannot be modified. It is recommended to use const keyword so that accidental changes to object are avoided. A const member function can be called by any type of object.
In object-oriented programming, a member variable (sometimes called a member field) is a variable that is associated with a specific object, and accessible for all its methods (member functions).
A constant variable is one whose value cannot be updated or altered anywhere in your program. A constant variable must be initialized at its declaration. To declare a constant variable in C++, the keyword const is written before the variable's data type.
Like member functions and member function arguments, the objects of a class can also be declared as const. an object declared as const cannot be modified and hence, can invoke only const member functions as these functions ensure not to modify the object. A const object can be created by prefixing the const keyword to the object declaration.
One of the primary examples is inheritance hierarchies. And in those cases, it is fine to use const or reference member variables. Another use case of const or reference members is in local function objects, where you don't care about assignment behavior.
The const qualifier on a member function means that you cannot modify non- mutable non- static class member variables. By way of offering some rationalisation, the this pointer in a const qualified member function is a const type, and this is inherently related to an instance of a class. static members are not related to a class instance.
Any attempt to change the data member of const objects results in a compile-time error. When a function is declared as const, it can be called on any type of object, const object as well as non-const objects.
decltype
has special rule for class members. It returns the actual type of the member. If you want decltype
to consider the context (inside a const function), then you can wrap the expression inside parentheses.
Without Paranthesis:
void test() const {
type_printer<decltype(value)> _;
}
c.cpp:10:39: error: implicit instantiation of undefined template 'type_printer<int>'
type_printer<decltype(value)> _;
With Paranthesis:
void test() const {
type_printer<decltype((value))> _;
}
c.cpp:10:41: error: implicit instantiation of undefined template 'type_printer<const int &>'
type_printer<decltype((value))> _;
Reference:
https://en.cppreference.com/w/cpp/language/decltype
If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression. If there is no such entity, or if the argument names a set of overloaded functions, the program is ill-formed.
https://docs.microsoft.com/en-us/cpp/cpp/decltype-cpp?view=vs-2019
If the expression parameter is an identifier or a class member access, decltype(expression) is the type of the entity named by expression. If there is no such entity or the expression parameter names a set of overloaded functions, the compiler yields an error message.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With