const有り無し両方のメンバ関数を用意する理由

参考書等をを見ると、例えば戻り値にメンバ変数への参照を返すようなメンバ関数を用意する場合、const有りとconst無しの両方を用意しています。

#include <iostream>
using namespace std;

class Foo {
    int m_num[10];
public:
    Foo() {}
    // const無し版
    int& operator[](int i) { return m_num[i];}
    

    // const有り版
    const int& operator[](int i) const { return m_num[i]; }
};

int main () {
    Foo foo;
    
    foo[1] = 10;
    cout << foo[1] << endl;
    
    return 0;
}
$ main
10

でもこういう場合、参照で返した値を書き換えたいのであって、const有り版をわざわざ用意する必要ないと思ってたのですが、ようやくどういう場合に必要なのかわかりました。

別のconstメンバ関数からの呼び出す場合に問題になります。

class Foo {
    int m_num[10];
public:
    Foo() {}
    // const無し版のみ用意
    int& operator[](int i) { return m_num[i];    }
    
    int get () const {
        // 本来はこんな書き方しないけど例として
        return (*this)[1];
    }
};
$ cl /W4 /EHsc main.cpp
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
main.cpp(12) : error C2678: 二項演算子 '[' : 型 'const Foo' の左オペランドを扱う演算子が見つかりません (または変換できません) (新しい動作; ヘルプを参照)。
        main.cpp(8): 'int &Foo::operator [](int)' の可能性があります。
        引数リスト '(const Foo, int)' を一致させようとしているとき

と、このようにエラーになります。

なのでconst有り版も用意しといた方が良いということですね。

他にどんな場合に問題が出るかちょっと思いつかなかったのですが、とりあえずはこれで。