そのままではprivate
なコンストラクタをmake_shared
で利用できないので内部クラスを利用する。
#include <memory>
class Hoge {
public:
static std::shared_ptr<Hoge> Create() {
return std::make_shared<CreateHelper>(1, 2);
}
static std::shared_ptr<Hoge> Create(int x, int y) {
return std::make_shared<CreateHelper>(x, y);
}
private:
// privateコンストラクタを呼び出すためのヘルパクラスとそのエイリアス
template<class T>
struct Impl : T {
template<class... ARGS>
explicit Impl(ARGS&&... args)
: T(std::forward<ARGS>(args)...) { /* ignore */ }
};
using CreateHelper = Impl<Hoge>;
int x_, y_;
Hoge(int x, int y) : x_(x), y_(y) { /* ignore */ }
}
説明
まず
-
std::make_shared
はprivate
内部クラスを構築可能 - 内部クラス(子クラス)は親クラスの
private
メンバにアクセス可能
そこで
- コンストラクタを呼び出すために親クラスを継承した
private
内部クラスを作成 -
private
エイリアスを作成 -
std::make_shared
で利用 - 暗黙的アップキャストによって親クラスのポインタとして使用
という流れ。
1.について、内部クラスの継承先をテンプレートにすることで、親クラスHoge
の継承を可能にしている。また、コンストラクタの引数をテンプレートにすることで、定義の手間を省いている。
2.について、直接内部クラスを呼び出すと、std::make_shared<CreateHelper<Hoge>>
となり、複数の関数から呼び出すという状況では保守性やコードの移植性が問題になるのでusing
を使ってstd::make_shared<CreateHelper>
の形式で呼び出せるようにしている。
参考記事
https://gintenlabo.hatenablog.com/entry/20131211/1386771626
https://qiita.com/ToshiManaPlus1/items/b98e50fa3af771fd0d60