我偶然发现了一个场景,我试图找出最干净的方法,如果有的话。
我有一个带有受保护的构造函数的模板类,需要由一个朋友模板类实例化。两者共享部分模板参数,但不是全部。这是我的问题的一个例子。
我希望从经验丰富的程序员那里了解是否还有其他可能的解决方案(除了使构造函数公开之外,我认为没有其他解决方案),并且如果在两者之间我提出了一个比另一个更可接受的解决方案。 谢谢
解决方案1-我向具有受保护的构造函数(类Element)的类提供“不必要的”模板参数。
template <typename Tp_>
class Engine_Type_X
{
};
template <typename Tp_>
class Engine_Type_Z
{
};
//Forward declaration
template <typename Tp_, template<typename> typename Eng_>
class Container;
//Eng_ is only required to declare the friend class
template <typename Tp_,template<typename> typename Eng_>
class Element
{
friend class Container<Tp_,Eng_>;
Tp_ tp_;
protected:
Element(Tp_ tp) : tp_{tp} //protected ctor!!!
{}
};
template <typename Tp_, template<typename> typename Eng_>
class Container
{
using Element_tp = Element<Tp_,Eng_>;
using Engine_tp = Eng_<Tp_>;
std::vector<Element_tp> container_;
Engine_tp &engine_;
public:
Container(Engine_tp &engine) : container_{},engine_{engine}
{}
void install(Tp_ tp)
{ Element_tp elem{tp};
container_.emplace_back(elem);
}
};
解决方案2-我使用的方法类似于在这里How to declare a templated struct/class as a friend?
template <typename Tp_>
class Engine_Type_X
{
};
template <typename Tp_>
class Engine_Type_Z
{
};
template <typename Tp_>
class Element
{
template<typename,template<typename>typename> friend class Container; //All templated classes are friend
Tp_ tp_;
protected:
Element(Tp_ tp) : tp_{tp} //protected ctor!!!
{}
};
template <typename Tp_, template<typename> typename Eng_>
class Container
{
using Element_tp = Element<Tp_>;
using Engine_tp = Eng_<Tp_>;
std::vector<Element_tp> container_;
Engine_tp &engine_;
public:
Container(Engine_tp &engine) : container_{},engine_{engine}
{}
void install(Tp_ tp)
{ Element_tp elem{tp};
container_.emplace_back(elem);
}
};
答案 0 :(得分:0)
您仍然可以探索一些选择。
您可以将一个类设为内部类(称为嵌套类),该类将自动 将其作为“外部”类的朋友。参见https://en.cppreference.com/w/cpp/language/nested_types
另一种方法是要求使用所谓的“令牌”作为 构造函数,此令牌类型通常不使用模板参数,然后对其进行设置,以使该令牌只能是 由另一个类创建(可以是嵌套类型,也可以是嵌套类型)。
根据OP的要求,以下是完成2种方法的概述。选项:(使用c ++ 0x)
template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};
template <class T>
class create_token {
public:
typedef T Type;
//copy of token not allowed !
create_token(const create_token &) = delete;
create_token& operator=(const create_token &) = delete;
//move is fine
create_token(create_token &&) = default;
create_token& operator=(create_token &&) = default;
friend class T;
private:
create_token();
};
template<class BlaBlaBla>
struct Element {
template<class T>
Element(create_token<T> t) {
static_assert(std::is_specialization<create_token<T>::Type, Container>::value, "Wrong type of token provided");
}
};
template<class Whatever>
struct Container {
template<class T>
Element(create_token<T> t) {
static_assert(std::is_specialization<create_token<T>::Type, Element>::value, "Wrong type of token provided");
}
};