はじめに
C++23から使える Deducing thisを使った、ちょっとしたテクニックを紹介します。
もし、あなたがメソッドチェーンを使ったコーディングを好むなら、this
を返すようなメソッドを作ったことがあったかもしれません。
しかし継承が絡むと順序を気を付ける必要が出てきます。
問題になるケース
例として以下のコードを見てみましょう。
class Actor
{
public:
Actor& setId(int id)
{
this->m_id = id;
return *this;
}
private:
int m_id;
};
class Hero : public Actor
{
public:
Hero& setHp(int hp)
{
this->m_hp = hp;
return *this;
}
private:
int m_hp;
};
以下のような順番でのメソッドチェーンは問題ないですが、
Hero hero;
hero
.setHp(10)
.setId(1)
;
メソッドを呼ぶ順番を変えると、繋がらなくなります。
Hero hero;
hero
.setId(1)
// .setHp(10) setIdの戻り値は Actor& なので setHp へ繋げられない
;
hero.setHp(10);
これは当然の結果ですが、親クラスのメソッドを呼んだ時点で、子クラスのメソッドへは繋げることができなくなります。
今回の例くらいなら、順番を気を付けるだけでいいかもしれませんが、
どうしても親クラスのメソッドを先に呼びたいケースがあるとすれば
メソッドチェーンで気持ちよくなりたい あなたは チェーンが途切れることにモヤモヤするかもしれません。
ここでも使えた Deducing this
親クラスのチェーンするメソッドを修正してみましょう。
template<class Self>
Self& setId(this Self& self, int id)
{
self.m_id = id;
return self;
}
こうする事で、子クラスから呼んだ場合の関数の戻り値が子クラスの型になります。
仮想関数(virtual
)の場合はDeducing thisが使えないことには注意
よって以下のコードが成功します。
Hero hero;
hero
.setId(1)
.setHp(10) // setIdの戻り値は Hero& なので setHp へ繋がる
;
もちろん子クラスが複数でも問題ありません。
class Actor
{
public:
template<class Self>
Self& setId(this Self& self, int id)
{
self.m_id = id;
return self;
}
private:
int m_id;
};
class Hero : public Actor
{
public:
Hero& setHp(int hp)
{
this->m_hp = hp;
return *this;
}
private:
int m_hp;
};
class Enemy : public Actor
{
public:
Enemy& setExp(int exp)
{
this->m_exp = exp;
return *this;
}
private:
int m_exp;
};
int main()
{
Hero hero;
hero
.setId(1)
.setHp(10) // setIdの戻り値は Hero& なので setHp へ繋がる
;
Enemy enemy;
enemy
.setId(2)
.setExp(100) // setIdの戻り値は Enemy& なので setExp へ繋がる
;
}
これで継承関係があっても自由に気持ちよくメソッドチェーンを繋げられます。
まとめ
Deducing thisを使ったテクニックとして
親クラスのメソッドを先に呼んでも子クラスのメソッドにチェーンする方法を紹介しました。
- これまでthisを返すようなメソッドチェーンのパターンで継承関係があると順序を気を付ける必要があった
- 親クラスに定義した
this
を返すメソッドを子クラスから呼んでも戻り値が親クラスの型になるので、子クラスのメソッドにチェーンできない
- 親クラスに定義した
- Deducing thisを使うことで上記問題を解決できる
- 親クラスに定義した
this
を返すメソッドを子クラスから呼んだら戻り値が子クラスの型になるので、子クラスのメソッドにチェーンできる - ただし仮想関数の場合はできない
- 親クラスに定義した
- 気持ちよいメソッドチェーンライフを送れる
参考
そもそもDeducing thisとはなんぞやみたいな話は以下が参考になります。