我可以想象有一种更短的方法来表示朋友是为所有可能的 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*/>;
老实说,我看不出与所有可能的专长交朋友会如何导致问题,但让我们假设它确实如此。我知道的一种解决方法是使用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());
}
//...
};
活生生的例子。