可能なすべての ClassImplType 列挙値に対してフレンドが定義されていることを示す、より短い方法があると想像できます。
残念ながら、実際にはありません。あなたは試してみてください
template<ClassImplType I> friend class graph<T, I>;
しかし、標準では、部分的な専門化と仲良くすることを単に禁止しています。
§14.5.4 [temp.friend] p8
フレンド宣言は、部分的な特殊化を宣言してはなりません。【例:
template<class T> class A { };
class X {
template<class T> friend class A<T*>; // error
};
—終わりの例]
あなたはそれらすべてを友達にすることしかできません:
template<class U, ClassImplType I>
friend class graph;
または特定のもの:
friend class graph<T /*, optional-second-arg*/>;
正直に言うと、考えられるすべてのスペシャライゼーションと仲良くすることがここで問題を引き起こす可能性があることはわかりませんが、そうであると仮定しましょう. 私が知っている 1 つの回避策はpasskey patternを使用することですが、少し縮小したバージョンを使用します (allow
テンプレートのすべての特殊化へのアクセスを許可するにはうまく機能しないため、ここではメカニズムを使用できません)。
template<class T>
class passkey{
passkey(){}
friend T;
// optional
//passkey(passkey const&) = delete;
//passkey(passkey&&) = delete;
};
// Different class implementations
enum ClassImplType { CIT_CHECK, CIT_FAST, CIT_GPU, CIT_SSE, CIT_NOF_TYPES } ;
template<class> struct vertex;
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph {
public:
void call_f(vertex<T>& v){ v.f(passkey<graph>()); }
//...
};
// Vertex class
template <typename T>
class vertex {
//...
public:
template<ClassImplType I>
void f(passkey<graph<T,I>>){}
};
テスト付きの実例。
アクセスする必要があるすべての機能を公開する必要があることに注意してください。ただし、指定された専門graph
化によってのみ作成できるパスキーのおかげで、それは問題ではありません。graph
さらに進んで、頂点機能にアクセスするために使用できるプロキシ クラスを作成することもできます (graph
変更のみ)。
// Graph class has default template argument CIT_CHECK
template <typename T, ClassImplType impl_type = CIT_CHECK>
class graph{
typedef passkey<graph> key;
// proxy for succinct multiple operations
struct vertex_access{
vertex_access(vertex<T>& v, key k)
: _v(v), _key(k){}
void f(){ _v.f(_key); }
private:
vertex<T>& _v;
key _key;
};
public:
void call_f(vertex<T>& v){
vertex_access va(v, key());
va.f(); va.f(); va.f();
// or
v.f(key());
}
//...
};
実例。