web-dev-qa-db-ja.com

std :: make_uniqueを私のクラスの友達にする方法

クラスのフレンドとしてstd::make_unique関数を宣言したい。その理由は、コンストラクターprotectedを宣言し、unique_ptrを使用してオブジェクトを作成する別の方法を提供することです。これがサンプルコードです:

#include <memory>

template <typename T>
class A
{
public:
    // Somehow I want to declare make_unique as a friend
    friend std::unique_ptr<A<T>> std::make_unique<A<T>>();


    static std::unique_ptr<A> CreateA(T x)
    {
        //return std::unique_ptr<A>(new A(x)); // works
        return std::make_unique<A>(x);         // doesn't work
    }

protected:
    A(T x) { (void)x; }
};

int main()
{
    std::unique_ptr<A<int>> a = A<int>::CreateA(5);
    (void)a;
    return 0;
}

今私はこのエラーを受け取ります:

Start
In file included from prog.cc:1:
/usr/local/libcxx-head/include/c++/v1/memory:3152:32: error: calling a protected constructor of class 'A<int>'
return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...));
                           ^
prog.cc:13:21: note: in instantiation of function template specialization 'std::__1::make_unique<A<int>, int &>' requested here
    return std::make_unique<A>(x);     // doesn't work
                ^
prog.cc:22:41: note: in instantiation of member function 'A<int>::CreateA' requested here
std::unique_ptr<A<int>> a = A<int>::CreateA(5);
                                    ^
prog.cc:17:5: note: declared protected here
A(T x) { (void)x; }
^
1 error generated.
1
Finish

クラスのフレンドとしてstd::make_uniqueを宣言する正しい方法は何ですか?

30
TheCrafter

_make_unique_ 渡した引数を完全に転送します。あなたの例では、左辺値(x)を関数に渡しているので、引数の型を_int&_として推定します。 friend関数宣言は

_friend std::unique_ptr<A> std::make_unique<A>(T&);
_

同様に、CreateA内でmove(x)を実行する場合、friend宣言は次のようにする必要があります。

_friend std::unique_ptr<A> std::make_unique<A>(T&&);
_

これにより、コードは compile になりますが、_make_unique_が引数を別の内部ヘルパー関数に転送するため、別の実装でコンパイルされることを保証するものではありません。実際にクラスをインスタンス化します。その場合、ヘルパーはfriendである必要があります。

19
Praetorian