【问题标题】:Class template explicit instantiation declaration类模板显式实例化声明
【发布时间】:2020-08-14 08:08:08
【问题描述】:

这是一个有点复杂的模式,不适合友谊。也许我必须重新考虑设计,但现在我只是对是否有可能完成这项工作感兴趣。问题是我不能声明我想在函数专业化声明中使用的 A 类模板显式实例化(使用不完整的 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&lt;el::Comp&gt;;

线。下一行

using Elem = ElemTempl&lt;el::Comp&gt;;

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

template&lt;&gt; void assem_elem&lt;ElemTempl&lt;el::Comp&gt;&gt;(ElemTempl&lt;el::Comp&gt;&amp; elem);

直接,这将起作用。但为什么?我不能在常规课程中做到这一点。至少我必须说类似&lt;class RegularClass&gt;,而不仅仅是&lt;RegularClass&gt;

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

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 尚未定义。这怎么行?

【问题讨论】:

    标签: c++ templates declaration friend incomplete-type


    【解决方案1】:

    你好像把explicit instantiationtemplate specialization搞混了。

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

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

    template&lt;&gt; void assem_elem&lt;Elem&gt;(Elem&amp; elem); 声明了一个特化,Elem 可能不完整。

    类 Assem 使用 Elem,因此它实例化了 Elem,但 Elem 需要实例化 Assem,而 Assem 尚未定义。这怎么行?

    Elem 本身只需要前向声明即可。

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

    构造函数和方法在类被隐式实例化时不会被实例化,但它们会在类被显式实例化时被实例化。

    【讨论】:

    • 编译器编译Assem时,Assem的构造函数的定义需要ElemTempl&lt;el::Comp, Assem&gt;的定义。编译器必须使用Assem 实例化它(因为它是第一次使用),但Assem 尚未完全定义。或者是吗?当编译器到达类成员的定义时,是否认为类已完全定义?
    • 类在其最终的} 处完成,(可能是inline),方法在类定义之后实例化(*:在某些情况下有一些微妙的auto 返回类型,您可以在其中有(非完整)类“未定义”,而只有前一行是“可见的”)。
    猜你喜欢
    • 2018-07-05
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 2014-09-23
    相关资源
    最近更新 更多