暗黙のインターフェースにconstを強要させる

テンプレートで静的ポリモーフィズムを実現するために暗黙のインタフェースを利用します。しかしこれは明示的なインターフェースと違い、引数がconst、あるいはインターフェースがconstメンバ関数かどうかまで通常指定することができません。しかしconstは便利で強力なので使いたい。それをしてみようというのがこの記事です。

言葉で説明しても分かりづらいですね。ということでconstを指定できないってことのサンプルコード

class Hoge{
public:
    void func();
    void func2(Someting& Obj);
};

class Bar{
public:
    void func()const;
    void func2(const Someting& Obj);

};

template<typename T>
class Foo{
public:
    func(){
    Obj.func();
    Obj.func2(Obj3);
    };
private:
    T Obj;
    Someting Obj3;
};

としたとき

int main(){
    Foo<Hoge> A;
    Foo<Bar> B;

    A.func();
    B.func();

    return 0;
}

としてもエラーがでないんですね。


(1)暗黙のインターフェースをconstメンバ関数にする
こちらは割合簡単です。意識しないで利用していることも多いんじゃないでしょうか?

template<typename T>
class Foo{
public:
    func() const{
    Obj.func();
    };
private:
    T Obj;
    Someting Obj3;
};

みたいにすればテンプレートで指定したTのfuncをconstメンバ関数にしなければエラーをきちんとはきます。Fooのfuncがconstなのでそのメンバ関数であるObjも変更しちゃいけないということです。この例ではFooのfuncをpublicにしちゃっていますが、メンバ関数をconstにしたいだけで外部から呼び出してほしくないときはprivateなメンバ関数にすればいいかと思います。

(2)暗黙のインターフェースの引数をconstにする
こっちは分かってしまえば単純なのですが、なかなか気づかないです。

template<class T>
class Foo{
public:
     void func(){
         Obj.func2(const_cast<const Something&>(Parameter));
     }
private:
	T Obj;
	int a;
	Something Parameter;

};

これで引数がconstになりました。通常はconst_castをconstではずす目的で利用することも多いですが、constをつけることもできるってのがミソです。多くのものでconstをはずすとしか紹介されてないので僕もEffective C++読むまでconstを付けられることを知りませんでした。

<追記>
VC++では予期したエラーはいてくれたのですがBCCではなぜかconstが効きませんでした...なんででしょうか?環境依存って怖いですよね。