LoginSignup
8
6

More than 5 years have passed since last update.

クラス内テンプレートクラスと継承を利用してmake_sharedでprivateコンストラクタを呼ぶ

Posted at

enabled_shared_from_thisを用いる場合、コンストラクタをprivateにしてshared_ptrを返すcreate関数を用意する方法が有効です。
だけど、create関数内でmake_sharedを使いたいけどprivateなコンストラクタが呼べないという問題があります。
その問題を回避するため、関数内クラスと継承を用いた手法があります。
std::make_shared から private コンストラクタを呼び出す

#include <memory>

struct X : std::enable_shared_from_this<X>
{
    std::shared_ptr<X> create();
private:
    X(){}
};

std::shared_ptr<X>
X::create()
{
    struct Helper:X { Helper():X(){} };
    return std::make_shared<Helper>();
//  return std::make_shared<X>();    Error! : ホントはこう書きたい
}

しかし、この手法だとprivateコンストラクタで引数を多くとるときに不便です。

#include <memory>

struct X : std::enable_shared_from_this<X>
{
    std::shared_ptr<X> create(int a,int b,int c);
private:
    X(int a_,int b_,int c_):a(a_),b(b_),c(c_){}
    int a,b,c;
};

std::shared_ptr<X>
X::create(int a,int b,int c)
{
    struct Helper:X { Helper(int a,int b,int c):X(a,b,c){} }; // ヘルパークラスに引数をたくさん書かないといけない!
    return std::make_shared<Helper>(a,b,c);
}

そこで、クラス内テンプレートクラスとして汎用のCreateHelperクラスを用意して、
ヘルパークラスの引数記載を省略するようにします。

#include <memory>

struct X : std::enable_shared_from_this<X>
{
    std::shared_ptr<X> create(int a,int b,int c);
private:
    X(int a_,int b_,int c_):a(a_),b(b_),c(c_){}
    int a,b,c;

   // クラス内テンプレートクラスを用いたヘルパークラス
    template<typename Base>
    struct CreateHelper:Base
    {
        template<typename... Args>
        explicit CreateHelper(Args&&... args):Base(std::forward<Args>(args)...){}
    };

};

std::shared_ptr<X>
X::create(int a,int b,int c)
{
    return std::make_shared<CreateHelper<X> >(a,b,c);
}

今回のCreateHelperはマクロにしてあげれば使いまわせるのでオススメです。

#include <memory>

#define CREATE_HELPER \
    template<typename Base> \
    struct CreateHelper:Base \
    { \
        template<typename... Args> \
        explicit CreateHelper(Args&&... args):Base(std::forward<Args>(args)...){} \
    }

struct X : std::enable_shared_from_this<X>
{
    std::shared_ptr<X> create(int a,int b,int c);
private:
    X(int a_,int b_,int c_):a(a_),b(b_),c(c_){}
    int a,b,c;

    CREATE_HELPER;
};

std::shared_ptr<X>
X::create(int a,int b,int c)
{
    return std::make_shared<CreateHelper<X> >(a,b,c);
}
8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6