类模板显式实例化声明

问题描述

这是一个有点复杂的模式,并不适合友谊。也许我不得不重新考虑设计,但是现在我只是对是否有可能进行这项工作感兴趣。问题是,我无法在要用作B定义中的朋友声明的函数特化声明中声明要使用的A类模板显式实例化(使用不完整的B类作为模板参数)。 / p>

namespace ns
{
    template<class ElemT>
    void assem_elem(ElemT& elem);

    template<class CompT>
    class ElemTempl
    {
    public:
        ElemTempl()
        {
            assem_elem(*this);
        }
        CompT comp;
    };


    namespace el { class Comp; }
    template class ElemTempl<el::Comp>; // error: 'ns::ElemTempl<ns::el::Comp>::comp' uses undefined class 'ns::el::Comp'
    using Elem = ElemTempl<el::Comp>;
    template<> void assem_elem<Elem>(Elem& elem);
    
    namespace el
    {
        class Comp
        {
            friend void ns::assem_elem<Elem>(Elem& elem);
            void link(){}
        };
    }

    template<> void assem_elem<Elem>(Elem& elem)
    {
        elem.comp.link();
    }
}

int main()
{
    ns::Elem el{};
    return 0;
}

更新

我想出了两种解决方案。首先,我可以删除

template class ElemTempl<el::Comp>;

行。下一行

using Elem = ElemTempl<el::Comp>;

似乎是实例化(?)的声明。另外,即使没有using行,我也可以写

template<> void assem_elem<ElemTempl<el::Comp>>(ElemTempl<el::Comp>& elem);

直接,这将起作用。但为什么?我不能在普通班上做到这一点。至少我必须说类似<class RegularClass>之类的东西,而不仅仅是<RegularClass>

第二个解决方案是使用一个类,并将其通过元素的模板参数传递:

namespace ns
{
    template<class CompT,class AssemT>
    class ElemTempl
    {
    public:
        ElemTempl()
        {
            AssemT{ *this };
        }
        CompT comp;
    };

    class Assem;
    namespace el
    {
        class Comp
        {
            friend ns::Assem;
            void link() {}
        };
    }
    using Elem = ElemTempl<el::Comp,Assem>;
    class Assem
    {
    public:
        Assem(Elem& elem) { elem.comp.link(); }
    };
}

但是这里也需要澄清一些事情。类Assem使用Elem,因此它实例化了Elem,但是Elem需要实例化Assem并且尚未定义Assem。这怎么办?

解决方法

您似乎对explicit instantiationtemplate specialization感到困惑。

使用template class ElemTempl<el::Comp>;(显式实例化),您可以实例化完整的类,而CompT comp;需要完整的类型,而el::Comp仅是向前声明的。

using Elem = ElemTempl<el::Comp>;只是别名的定义。没有实例化。

template<> void assem_elem<Elem>(Elem& elem);声明了特殊化,Elem可能不完整。

类Assem使用Elem,因此它实例化Elem,但是Elem需要实例化Assem,并且尚未定义Assem。这怎么办?

Elem本身仅需要向前声明才有效。

该类在实例化时需要完整的类型el::Comp
构造函数ElemTempl::ElemTempl在实例化时需要完整的Assem

构造类和方法时,不会隐式实例化,而构造类和方法是显式实例化。