What is the difference between this three functions regarding using "const" qualifier
int& func (const int& var)
I know that the const qualifier keep input read-only and can not be changed inside the function.
int const func (int& var)
and this one also return const variable, but what does it mean? it means it can not be changed through the code?
int& func (int& var) const
and what about this one? I have no idea what this means.
int& func (const int& var)
^^^^^^^^^^^^^^
The highlighted part is an argument declaration. The part const int& is the type of the argument variable and var is the name of the variable.
Normally, constness applies to the left, but in this case, it is the left most token of the type. In this exceptional case, it applies to the right instead. To the right is int. Therefore it is a const int. As a whole, the type of the argument is reference to const int.
int const func (int& var)
^^^^^^^^^
The highlighted part is the return type declaration of the function. The return type is a const int object. Although it is well-formed, it never really makes sense to return a const int since the constness is irrelevant to the caller. Most compilers have options to warn in case of such declaration.
Technically, returning a const class object may be different from returning a non-const one, but I have not seen a case where that would be useful.
int& func (int& var) const
Const after the argument list applies to the function itself. A const member function may not be called on a non-const object or reference. The implicit *this argument of the member function will be const. Const qualifier cannot be applied on a non-member function or a static member function.
Regarding old version of the question...
What is the difference between this three functions regarding using "const" modifier
int& func (int& const var)
int& const func (int& var)
These two are ill-formed. Const qualifier cannot apply to a reference (although, you can have a reference to a const type, and such references are colloquially called const references).
You need to read the const quantifiers from right to left to understand them.
so for example int const func(int& var) returns a const int
Here is an example of the use:
#include <stdexcept>
#include <iostream>
int& func(const int& var)
{
std::cout << "func(const int& var) called\n";
throw std::runtime_error("not implemented");
}
int const func(int& var)
{
std::cout << "func(int& var) called\n";
throw std::runtime_error("not implemented");
}
struct A {
int& func(int& var) const
{
// i = 2; illigal since const function
std::cout << "func(int& var) const called\n";
throw std::runtime_error("not implemented");
}
int i;
};
int main()
{
try
{
const int i = 1;
func(i);
}
catch (std::exception) {}
try
{
int j = 2;
func(j);
}
catch (std::exception) {}
try
{
A a;
int k = 2;
a.func(k);
}
catch (std::exception) {}
}
Related
Why is it not possible to assign a value to a reference returned by a const functor?
#include <vector>
template<typename T>
class Test {
public:
T & operator()(size_t index) const {
return A[index];
}
private:
std::vector<T> A{1,2,3};
};
int main() {
const Test<double> test1;
const Test<double> test2;
Test<double> test;
test(0) = test1(0) + test2(1);
}
I get the compiling errors below but I don't understand why the const of the functor is prohibiting the assignment because the functor itself isn't changing its object.
main.cpp:7:12: error: binding value of type 'const
__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type' (aka 'const double') to
reference to type 'double' drops 'const' qualifier
return A[index];
^~~~~~~~
main.cpp:19:7: note: in instantiation of member function 'Test<double>::operator()' requested
here
test(0) = test1(0) + test2(1);
^
If the functor wouldn't be const I would get a compiling error because of the const Test<double> test1, but this is clear to me.
How can I get the code above to be running? I need to use the functor to assign values from const objects.
this in the context of that method is a Test<double> const * which means that this->A is implicitly const. Therefore, A[index] has type double const & which cannot be converted to T & (which is double &).
To put it another way, instance members of a const object are themselves const (unless they are declared mutable).
The correct solution is to have two operator() implementations, one const and one not:
T & operator()(size_t index) { return A[index]; }
T const & operator()(size_t index) const { return A[index]; }
The former will be called on non-const instances and does allow assignment; the latter will be called on const instances and does not allow assignment.
(Demo)
As others have stated, what you have won't work because this is const inside of a method marked as const, so A will also be const, and A[index] will return a const reference, and you can't assign a const reference to a non-const reference, like you are attempting to do.
In this situation, you need two operator() implementations, one that is const and one that is not. The + operator can use the const version to read values from the const objects, and the = operator can use the non-const version to write the result to the non-const object:
template<typename T>
class Test {
public:
const T& operator()(size_t index) const {
return A[index];
}
/* or:
T operator()(size_t index) const {
return A[index];
}
*/
T& operator()(size_t index) {
return A[index];
}
private:
std::vector<T> A{1,2,3};
};
int main() {
const Test<double> test1;
const Test<double> test2;
Test<double> test;
test(0) = test1(0) + test2(1);
}
Live demo
When you have an object of type const Test<...>, the member variable A is also a const object.
That prevents A[0] from be assigned to. A[0] evaluates to a const&, not a non-const&.
The ff() function returns a rvalue but when I change the return value of function to be const, does it return lvalue? Why does the following output change its output from "lvalue reference" to "rvalue reference" when I change test ff() { } into const test ff() { }
#include <iostream>
using namespace std;
class test { };
void fun( const test& a)
{
cout << "lvalue reference"<<endl;
}
void fun( test&& a)
{
cout << "rvalue reference"<<endl;
}
const test ff() { } // <<---return value is const now
int main()
{
fun(ff());
}
Output:
lvalue reference
void fun( test&& a) is a function that takes a reference to a non-const rvalue. ff returns a const test which is a const rvalue. You cannot bind a reference to a non-const rvalue to a const rvalue as that would violate const-correctness. This is why it instead binds to void fun( const test& a), which takes a reference to a const test
Do note that when returning by value there is no benefit to return a const thing over a thing. The only time adding const to the return type matters is when returning by reference. If you have a member function that is marked as const or returning a reference to a constant data member then you must use const to preserve const-correctness.
Your test function output is misleading and test functions should be instead:
void fun( const test& a)
{
cout << "lvalue const reference"<<endl;
}
void fun( test& a)
{
cout << "lvalue reference"<<endl;
}
void fun( test&& a)
{
cout << "rvalue reference"<<endl;
}
void fun( const test&& a)
{
cout << "rvalue const reference"<<endl;
}
then you will see what is really happening there.
In a case like this where you're interested in why the compiler chose one overload instead of another, it's often easiest to (more or less) ask the compiler directly how/why it made the decision it did, by only allowing it to select the other function, and seeing what error message it gives (or whether it may give no error message at all). In this case, we can remove the function taking a const lvalue reference to get code like this:
#include <iostream>
using namespace std;
class test { };
// void fun( const test& a)
// {
// cout << "lvalue reference"<<endl;
// }
void fun( test&& a)
{
cout << "rvalue reference"<<endl;
}
const test ff() { } // <<---return value is const now
int main()
{
fun(ff());
}
Now if we try to compile, the compiler will directly tell us why the remaining function wasn't selected:
trash9.cpp:16:3: error: no matching function for call to 'fun'
fun(ff());
^~~
trash9.cpp:8:6: note: candidate function not viable: 1st argument ('const test') would lose const qualifier
void fun( test&& a)
^
That's not as authoritative as a direct quote from the standard, but compilers are good enough at things like this that the error messages can be fairly informative.
In C++, I have some troubles understanding the difference between these 3 ways where const is used :
int get() const {return x;}
const int& get() {return x;}
const int& get() const {return x;}
I'd like to have a clear explanation with examples to help me understand the differences.
Here's the most const example:
class Foo
{
const int * const get() const {return 0;}
\_______/ \___/ \___/
| | ^-this means that the function can be called on a const object
| ^-this means that the pointer that is returned is const itself
^-this means that the pointer returned points to a const int
};
In your particular case
//returns some integer by copy; can be called on a const object:
int get() const {return x;}
//returns a const reference to some integer, can be called on non-cost objects:
const int& get() {return x;}
//returns a const reference to some integer, can be called on a const object:
const int& get() const {return x;}
This question explains a little more about const member functions.
Const references can also used to prolong the lifetime of temporaries.
(1) int get() const {return x;}
We have two advantages here,
1. const and non-const class object can call this function.
const A obj1;
A obj1;
obj1.get();
obj2.get();
2. this function will not modify the member variables for the class
class A
{
public:
int a;
A()
{
a=0;
}
int get() const
{
a=20; // error: increment of data-member 'A::a' in read-only structure
return x;
}
}
While changing the member variable of the class [a] by constant function, compiler throws error.
(2) const int& get() {return x;}
returning the pointer to constant integer reference.
(3)const int& get() const {return x;}
it is combination answer (2) and (3).
I have seen the following code:
template <class T>
class Type {
public:
Type() {}
T& operator=(const T& rhs) {value() = rhs; return value();}
T& value() {return m_value;}
T value() const {return m_value;}
private:
T m_value;
};
Why does the compiler not complain about
T& value() {return m_value;}
T value() const {return m_value;}
and how to know which one is invoked?
The two functions are actually not the same. Only the second function is declared as a const member function. If the object that the member is called from is const, the latter option is used. If the object is non-const, the first option is used.
Example:
void any_func(const Type *t)
{
something = t->value(); //second `const` version used
}
void any_func2(Type *t)
{
something = t->value(); //first non-`const` version used
}
If both functions were declared non-const or both were declared const, the compiler would (should, anyway) complain.
Why does the compiler not complain about
Because the const counts for a different function signature. Your assumption the function signatures are identical is wrong.
The function marked as const will be invoked for any const instance or reference of Type<T>.
and how to know which one is invoked?
Put a cout statement in the functions and test the following cases:
template <class T>
class Type {
public:
Type() {}
T& operator=(const T& rhs) {value() = rhs; return value();}
T& value() {
std::cout << "non const version" << std endl;
return m_value;
}
T value() const {
std::cout << "const version" << std endl;
return m_value;
}
private:
T m_value;
};
int main() {
Type<int> t;
t.value();
Type<int> rt = t;
rt.value();
Type<int>* pt = &t;
pt->value();
const Type<int> ct;
ct.value();
const Type<int>& crt = t;
crt.value();
const Type<int>* pct = &t;
pct->value();
}
Your assignment operator will call the non const version.
The const version should better look like
const T& value() const {
std::cout << "const version" << std endl;
return m_value;
}
because you can't always rely on RVO (return value optimization), and extra copies might be taken (especially for older compiler implementations).
Also note the assignment operator should return a reference to the current instance:
Type& operator=(const T& rhs) {value() = rhs; return *this;}
A couple of words on functions resolution priority. Compiler distinguishes between const/non const functions on following way:
If a class has only const function with given name and argument list, it will be called for constant and non-constant objects alike. After calling this function, object will 'assume' constness (even if it was not const), meaning that the function can only call other const functions.
If a class has only non-const function, it will be called for non-const objects. Attempt to call this function for const objects will lead to compilation error.
If a class has both functions available, const version will be used for const objects, non-const version will be used for non-const objects.
Thanks to #owacoder for pointing my attention to initial mixup in the description.
This question already has answers here:
Should I return const objects?
(12 answers)
Closed 9 years ago.
struct CCompare
{
const bool operator()(const int& lhs, const int& rhs) const {
return lhs < rhs;
}
};
Warning 1 warning C4180: qualifier applied to function type has no
meaning;
I saw the usage with return value as const bool in a programming book. When I compiled the above code with vs2010, it reports the warning C4180.
The following code instead will not cause the same warning.
struct CCompare
{
bool operator()(const int& lhs, const int& rhs) const {
return lhs < rhs;
}
};
Question1> Is it true that the usage of const Fundamental_Data_Types as a function returned value doesn't make sense?
Question2> Is it true that the usage of const Type as a function returned value only makes sense iff the Type is a class/struct?
Thank you
// Update //
struct CClass
{
int val;
CClass(int _val) : val(_val) {}
void SetValue(int _val) {
val = _val;
}
};
struct CCompare
{
const CClass getMe() const {
return CClass(10);
}
CClass getMeB() const {
return CClass(10);
}
};
int main(/*int argc, char *argv[]*/)
{
CCompare c;
c.getMe().SetValue(20); // error
c.getMeB().SetValue(20); // ok
}
Yes and yes to both of your questions. Return values are
rvalues, and cv-qualifiers only apply to rvalues if they have
a class type.
The reason for this is fairly simple: there's normally nothing
you can do with an rvalue where const-ness would make
a difference—it's a value, after all, and not an object.
With a class type, there are member functions to take into
account (which means that you can get an lvalue from the
rvalue), so const-ness suddenly becomes relevant.