7

何らかの形で部分テンプレート仕様をフレンドクラスにすることは可能ですか?私。あなたは今、あなたは私が達成したい何のポインタC++テンプレート:部分テンプレート仕様とフレンドクラス

template <class T> class X<T*>{ 
    T* t; 
}; 

ための例えば部分的特殊化を、持っている以下のテンプレートクラス

template <class T> class X{ 
    T t; 
}; 

を持って考えることは、すべての可能なX<T*>がANYのX<S>のフレンドクラスであるということですS。私。 X<A*>X<B>の友人になるはずです。もちろん

、私はXにおける通常のテンプレートfriend宣言について考えた:

template <class T> class X{ 
    template <class S> friend class X<S*>; 
} 

しかし、これはコンパイルされません、私にこのことを伝え++ G:

test4.cpp:15:34エラー: 'template<class T> class X' の専門は、名前空間スコープで現れなければならない

test4.cpp:34:21:エラー:一部の専門 'X<S*>' は「友達の

宣言しました

これはまったく不可能なのでしょうか、それとも回避策がありますか?

私が求めていた理由は、私は(TのサブタイプでなければなりませんS)任意X<S>からこのクラスを作成しますX<T*>でコンストラクタを必要とするということです。

コードは次のようになります。

template <class T> class X<T*>{ 
    T* t; 

    template<class S> 
    X(X<S> x) : t(&(x.t)) {} //Error, x.t is private 
} 

を今、コンパイラはそれがプライベートであるため、x.tはコンストラクタでvisibileではないことを、当然のことながら、文句を言います。これが私が部分的な専門化の友達クラスを必要とする理由です。

+1

'get'関数は本当に質問から外れていますか?これは私にとってはよりクリーンで、テンプレートの友人の狂気をすべて避けているようです。 – pmr

+0

この例ではおそらく動作します。しかし、公開されてはならないデータがありますが、テンプレートの特殊化のみが可能です。問題は何とかこの動作が可能かどうかです。 – gexicide

答えて

3

C++では、privateを超えるアクセス権を4つのレベルで付与できます。

  • 完全publicアクセス(PMRの回答を参照してください)
  • 完全に非テンプレートにベーステンプレートfriendに(ここでは無関係protected、)継承階層内のアクセス
  • (この答えを参照)
  • か専門的なfriend(弱すぎるあなたのユースケースを解決するために)

何のミドルウェイベットはありません後者の2つの友情を磨く。

C++標準の§14.5.4より:。

Friend declarations shall not declare partial specializations.

次の宣言では、必要なものを実装できます。他の専門分野からテンプレートの専門分野にアクセスするには無料の手がありますが、依然としてXの範囲内に限ります。あなたが求めていたものよりも若干許容されています。

template<class T> class X 
{ 
    template<class Any> friend class X; 
    public: 
     ... 
}; 
1

私たちは、これはまだいくつかの弱点を持っているX.

で定義されたキーによって保護さ getter
#include <type_traits> 

template <class T> class X{ 
    T t; 
public: 
    struct Key { 
    template<typename S> 
    Key(const X<S>&) { 
     static_assert(std::is_pointer<S>::value, "Not a pointer"); 
    } 
    }; 

    const T& get(Key) const { return t; } 
    T& get(Key) { return t; } 
}; 

template <class T> class X<T*> { 
    T* t; 
public: 
    template<class S> 
    X(X<S>& x) : t(&(x.get(typename X<S>::Key(*this)))) {} 
}; 

int main() 
{ 
    X<int> x1; 
    X<int*> x2(x1); 
    return 0; 
} 

を定義することができます。 X<T*>の人は誰でも getを使用できるようになりました。しかし、これは今ではあまりにも難読化されているので、誰もが に気づいていません。私は単純なパブリックゲッターを選ぶだろう。

+1

基本的に、 'nullptr'を持つ人は' get'を使うことができます。ここでは許容度のコンテストがあるように見えます。 –

+0

@ JirkaHanikaあなたは 'null_ptr'オーバーロードでそれを解決しようとすることができますが、それを改善するものではありません。 – pmr

+1

はい、 '0'リテラルを持つ人は誰でも' get'を使うことができます。 –

関連する問題