Search code examples
c++constants

How does the keyword "const" work in C++?


Consider:

namespace pairDemo{

template<typename L, typename R>
class pair{
public:

    pair(const L& left,const R& right)
        :lft(left),rht(right)
    {
    }

    pair(const pair<L,R>& p)
        :lft(p.lft),rht(p.rht)
    {
    }

    L left() const{
        return lft;
    }
    R right() const{
        return rht;
    }

    void left(const L& left){
        lft = left;
    }
    void right(const R& right){
        rht = right;
    }
private:
    L lft;
    R rht;
};
}

//---------------------------------------------------

#include "pairTemp.h"
#include <iostream>
using namespace std;

pairDemo::pair<int, double> func(int x, double y){
    pairDemo::pair<int, double> temp(x*2, x+y);
    return temp;
}

int main(){
    int x = 2; double y = 3.55;
    pairDemo::pair<int, double> myPair = func(x,y);
    cout << myPair.left() << myPair.right();
}

For the constructor arguments, if I do not declare "const", the function func() will have an error. Why is that?


Solution

  • If you remove the consts from the constructor pair::pair(const L& left, const R& right), then the code pairDemo::pair<int, double> temp(x*2, x+y); won't work, because the result of x*2 is prohibited from binding to L& left, and x+y is prohibited from binding to R& right.

    C++ has this rule, because the designers felt that function parameters of non-const reference types should indicate that the the function can change the value, and that that change should be visible to the caller.

    Consider:

    void foo(int &i) {
        i = 3;
    }
    
    foo(x); // sets x to 3
    foo(1); // sets 1 to 3??? prohibited
    

    This could cause confusion if someone accidentally calls foo with a temporary like 1 or or x+y or x*2, so C++ decides to do the safe thing and not allow these to compile.

    C++11 adds 'rvalue references' which have some different rules.

    void bar(int &&i) { // && means 'rvalue reference'
        i = 3;
    }
    
    bar(1); // sets 1 to 3!
    bar(x); // prohibited.
    

    rvalue references are supposed to mean that the function is getting a temporary value and whatever it does with it will not affect the outside world. Now the danger is that a function taking an rvalue reference would accidentally be called with a non-temporary. Therefore, the rules try to prohibit you from passing in a non-temporary value, like x.