微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

模板显式实例化如何工作以及何时工作?

如何解决模板显式实例化如何工作以及何时工作?

这是C ++入门第5版的练习:

“练习16.26:假设NoDefault一个没有认构造函数的类,我们可以显式实例化vector<NoDefault>吗?如果没有,为什么不呢?”

这是我的猜测:

是的,我们可以实例化它:

template <typename T>
class Foo
{
public:
    void func(){cout << x_.value_ << endl;}
private:
    T x_;
};

class Bar
{
public:
    Bar(int x) : value_(x){}
    void print(){}
private:
    int value_{};
template <class T>
friend class Foo;
};

extern template class Foo<Bar>; // instantiation declaration
template class  Foo<Bar>; // instantiation deFinition


int main()
{

  //  Foo<Bar> f;
}

代码工作正常,但是如果我取消注释main中的行,则会由于预期的错误而出现错误,因为Bar无法认构造。

如果我使用相同的类Bar作为std::vector的元素类型,则它将不起作用:

extern template class vector<Bar>; // declaration ok
template class vector<Bar>; // instantiation: doesn't work?!
  • 那为什么我的Foo<Bar>实例有效但为什么vector<Bar>不起作用?

  • 在我看来,vector<Bar>中不起作用是合乎逻辑的,因为显式的实例化定义实例化了类模板的所有成员(甚至是未使用的成员)。在此示例中,其中的认构造函数Foo<Bar>表示元素类型为ctorBar;后者没有提供;毕竟Foo<Bar>()通常被声明为已删除的成员函数,因为x_没有认的构造函数。所以我不知道为什么Foo<Bar>定义有效吗?谢谢。

解决方法

在标准中,[temp.explicit]部分介绍了在显式实例化中发生的情况。 p12特别规定:

命名类模板专门化的显式实例化定义显式实例化类模板专门化,并且是仅在实例化点已定义的那些成员的显式实例化定义。

现在,const prepareOnTick = (onPerItemSettle: OnPerItemSettle) => { // TS compiler does not like <T>,he likes more <T,> or <T extends unknown> because of // JSX :D return <T,>(promise: Promise<T>): Promise<T>=> { promise .then( () => { onPerItemSettle.onSuccess?.(); },() => { onPerItemSettle.onError?.(); } ) .finally(() => { onPerItemSettle.onSettled?.(); }); return promise; }; }; 具有一个构造函数,该构造函数采用整数std::vector<T>并使用n值初始化的n来初始化向量。可以假定此构造函数的定义在T标头内(请参见Why can templates only be implemented in the header file?)。因此,<vector>的显式实例化定义将使用std::vector<Bar> = T实例化该构造函数。

因为这是一个 explicit 实例化,所以实例化的不仅是构造函数的签名,还包括它的整个主体。它必须在某个地方包括对Bar的默认构造函数的调用(可能是它所调用的另一个函数的一部分,这时也将被实例化),因此在显式实例化的一部分中会发生编译错误。 Bar的定义。请注意,如果您隐式实例化std::vector<Bar>,它将仅实例化(大致而言)成员函数的签名。这就是为什么实际上定义和使用std::vector<Bar>对象是合法的,只要您不调用任何需要存在std::vector<Bar>默认构造函数的函数即可。

Bar 成功的显式实例化定义的原因是,在实例化Foo<Bar>时,编译器将其默认构造函数标记为已删除(这总是在以下情况下发生:是不可默认构造的非静态成员)。因此,它在任何时候都不会尝试编译任何需要默认构造函数Foo<Bar>的代码,并且不会发生错误。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。