如果我有一个类采用模板参数的可变参数包,我怎样才能将它们声明为朋友?
这是我想以伪代码形式执行的操作:
template<typename... Ts>
class AbstractMyClass {
int privateInt;
friend Ts...;
};
class OtherClass;
using MyClass = AbstractMyClass<OtherClass>;
class OtherClass {
public:
void foo(MyClass &c){
c.privateInt = 42;
}
};
以下是万能钥匙习语的稍微扩展形式,怎么样?
使用 TPassKeys,它允许将多个类指定为限制访问的函数的参数,并且在访问它时,会在允许的类中创建 TPassKey 的实例,并将其传递给 TPassKeys 的构造函数。
一个不方便的地方是,与通常的密钥习惯用法不同,调用参数不能缩写为 {}。
template <class TAuthorized>
struct TPassKey
{
private:
friend TAuthorized;
TPassKey() {}
public:
TPassKey(const TPassKey&) = delete;
TPassKey& operator=(const TPassKey&) = delete;
};
template <typename TTest, typename... TList>
struct TContains;
template<typename TTest, typename TFirst, typename... TRest>
struct TContains<TTest, TFirst, TRest...> : std::conditional_t<std::is_same_v<TTest, TFirst>, std::true_type, TContains<TTest, TRest...>> {};
template <typename TTest>
struct TContains<TTest> : std::false_type {};
template<class... TAuthorizedList>
struct TPassKeys
{
template <class TAuthorized, typename TEnableIf<TContains<TAuthorized, TAuthorizedList...>::value, std::nullptr_t>::Type = nullptr>
TPassKeys(TPassKey<TAuthorized>) {}
};
// Tests.
class FTest
{
public:
static void Test(TPassKeys<class FClassA, class FClassB>) {}
};
class FClassA
{
public:
void Test()
{
FTest::Test(TPassKey<FClassA>()); // OK.
}
};
class FClassB
{
void Test()
{
FTest::Test(TPassKey<FClassB>()); // OK.
}
};
class FClassC
{
void Test()
{
FTest::Test(TPassKey<FClassC>()); // Error.
}
};
这只能使用“编译时递归”来完成,就像元组一样。要点是(我现在在一台小型笔记本电脑上,根本无法舒适地打字):
template<class .... THINGS> class object;
template<class T> class object {
friend T;
};
template<class T,class ... THINGS>
class object: public object<THINGS> {
friend T;
};
如果 C++ 不喜欢这样,请尝试使用
template<> class object<> {};
作为结束递归的递归(我在 1 个模板参数中使用 object
来终止递归)
(感谢 Dietmar Kuhl 进行格式化)