Class 模板显式实例化声明

Class template explicit instantiation declaration

这种模式有点复杂,不太适合友谊。也许我必须重新考虑设计,但现在我只是感兴趣是否有可能使这项工作成为可能。问题是我无法声明 class A 模板显式实例化(不完整 class B 作为模板参数),我想在我想用作朋友的函数专业化声明中使用B.

定义中的声明
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);

直接,这会起作用。但为什么?我不能用常规的 classes 来做到这一点。至少我必须说 <class RegularClass>,而不仅仅是 <RegularClass>.

第二种解决方案是使用 class 并通过元素的模板参数传递它:

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(); }
    };
}

但这里也有一些事情需要澄清。 Class Assem使用Elem,因此它实例化了Elem,但是Elem需要实例化Assem并且Assem没有定义然而。这怎么行?

你似乎混淆了 explicit instantiation and template specialization

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

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

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

Class Assem uses Elem, thus it instantiates Elem, but Elem needs Assem to be instantiated and Assem is not defined yet. How can this work?

Elem 本身只需要前向声明就有效。

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

构造函数和方法在 class 被 隐式 实例化时不被实例化,但是当 class 被 显式 实例化。