I stumbled into a scenario and I'm trying to figure out for the cleanest approach, if there's any.
I have a template class with a protected constructor, that needs to be instantiated by a friend template class. Both share part of template parameters, but not all. Here's a example of my problem.
I wish to know from experienced programmers if there are other possible solutions (I suppose not, besides turning constructor public), and if between the two I present one its more acceptable than the other. Thanks
Solution 1- I supply "unnecessary" template parameters to the class with protected constructor (class 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);
}
};
Solution 2 - I use an approach like the one I've found here 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);
}
};