web-dev-qa-db-ja.com

テンプレートクラスのテンプレートフレンド関数を宣言する

クラステンプレートObjと関数テンプレート_make_obj_があります。 Objにはprivate単一のコンストラクターが定義されており、バインドするテンプレート化された型への参照を受け取ります。

_template <typename T>
class Obj {
  private:
    T& t;
    Obj(T& t)
        : t{t}
    { }
};

template <typename T>
Obj<T> make_obj(T& t) { 
    return {t};
}
_

私が望むのは、friendを作成できるように_make_obj_関数をObjとして宣言することです。


私はいくつかの友人宣言を試しました

_friend Obj make_obj(T&);
_

そして

_template <typename T1, typename T2>
friend Obj<T1> make_obj(T2&);
_

後者は、Objクラスの_make_obj_友人のすべてのテンプレートのインスタンス化を行う試みとしてはあまり望ましくありません。ただし、これらの両方のケースで同じエラーが発生します。

_error: calling a private constructor of class 'Obj<char const[6]>'
    return {t};
           ^

note: in instantiation of function template specialization
      'make_obj<const char *>' requested here
    auto s = make_obj("hello");
             ^
_

例としてmake_obj("hello");を実行しようとしています。

Objの値コンストラクターへの_make_obj_アクセスのみを許可するにはどうすればよいですか?

28
Ryan Haining

いくつかの前方宣言が必要です。

template <typename T>
class Obj;

template <typename T>
Obj<T> make_obj(T t);

template <typename T>
class Obj {
private:
    T & t;
    Obj (T & t) : t(t) { }
    Obj() = delete;

    friend Obj make_obj<T>(T t);
};

template <typename T>
Obj<T> make_obj(T t) { 
    return Obj<T>(t);
}

実例

ところで、私はあなたが本当に欲しいとは思わないT & t;クラスのメンバー変数。多分 T t;の方が良い選択です;)

42
Daniel Frey

自動戻り型構文を使用すると、関数を前方宣言するだけで、すべてが機能します。ここに例があります

template <typename T>
auto make_obj(T t);

template <typename T>
class Obj {
private:
    T & t;
    Obj (T & t) : t(t) { }
    Obj() = delete;

    friend auto make_obj<T>(T t);
};

template <typename T>
auto make_obj(T t) {
    return Obj<T>{t};
}

int main() {
    make_obj(1);
    return 0;
}

https://ideone.com/3k86gx

3
Curious