[C++] constな引数を受け取る関数とそうでない関数を同時に定義する

 ご無沙汰です。生きてます。タイトルの付け方が非常に微妙というか簡潔にまとめられなかったのですが、処理は同じだけど"constな引数を受け取ってconstな値を返すメンバ関数"と"非constな引数を受け取って非constな値を返すメンバ関数"を書きたいことってないですか。とりあえずあるってことにしておいてください。言葉だとアレなんですがコードだとこんな感じ。

const char *SomeClass::hoge(const char *arg)
{
    // なんかやる
    return arg;
}

char *SomeClass::hoge(char *arg)
{
    // なんかやる
    return arg;
}

みたいな。別にコードを2つかいてもいいんですけど、それだとなんだかめんどくさいなぁって時にどうしたらいいのかメモ。もっといい方法があるかも。いやあると思うけど。

テンプレートを使う

 テンプレートを使えばいいんです。そうです。

template<typename T>
T SomeClass::hoge(T arg)
{
    // なんかやる
    return arg;
}

でもテンプレートを使うと

  • 実装をヘッダに書かなきゃない
  • Tにはいろんな型が指定される可能性があるので、Tを制限したい
  • 上記に付随して、テンプレートの型制限はめんどくさい

あたりが気になってきます。特に1つ目の問題は大きいわけです。そこで、テンプレートの分割コンパイルを利用して

  • ソースコード側にコードを書きつつ
  • コードを1つにまとめつつ
  • Tを制限できる

ような方法を考えてみます。

テンプレート分割コンパイル

 テンプレートは実体化を行わなければならないので、ヘッダファイルに記述するのが一般的です。逆に言えば、実体化さえ可能ならヘッダとソースに分割して記述しても問題ありません。以下にコードを載せます。

// .hに書く
class Hoge
{
public:
    template<typename T>
    static T add(T arg);
};

// .cppに書く
template<typename T>
T SomeClass::add(T arg)
{
    return arg + 1;
}

// 実体化
template int SomeClass::hoge(int);
template float SomeClass::hoge(float);

 16行目以降がポイントで、このように記述することでテンプレートを特定の型に対して実体化でき、かつここで指定した型以外を受け取るとコンパイル時にエラーが発生します。これで先に挙げた条件3つがクリア出来ました。

// .hに書く
class Hoge
{
public:
    template<typename T>
    static T hoge(T arg);
};

// .cppに書く
template<typename T>
T Hoge::hoge(T arg)
{
    // なんかやる
    return arg;
}

template char *Hoge::hoge(char *);
template const char *Hoge::hoge(const char *);

 こんな感じでconstとそうでないコードに対応できます。

 ただ、これだと使うときにIDEのコード補完とかで不便なので、私はこんな感じで書いています。

// .hに書く
class Hoge
{
private:
    template<typename T>
    static T _hoge(T arg);
public:
    inline static char *hoge(char *arg) { return _hoge(arg); }
    inline static const char *hoge(const char *arg) { return _hoge(arg); }
};

// .cppに書く
template<typename T>
T Hoge::hoge(T arg)
{
    return arg;
}

template char *Hoge::_hoge(char *);
template const char *Hoge::_hoge(const char *);

 ちなみに、staticなメンバ関数にしてるのは、通常の関数に対してはテンプレートの明示的な実体化が出来ないためです。ダミー関数を定義して、その中で実体化する方法で回避できるようですがあまり美しくないので使ったことはないです。

 この辺の話は、静的多態性とかコンセプトとかそういう感じの話なので、CRTPのようなテクニックを使っても実装できそうです。静的多態性よりかは、与えられた引数の型に対してコンセプトの不整合が起こっていないか静的に確認したい、ってあたりの話ですかね。

 参考: CRTP(Curiously Reccursive Template Pattern)の使われ方

0 件のコメント :

コメントを投稿