加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – unique_ptr何时需要完整的类型?

发布时间:2020-12-16 05:53:20 所属栏目:百科 来源:网络整理
导读:在下面的代码中,函数f()可以调用运算符bool()和operator *()的成员函数unique_ptr C对于不完整的类C,但是当函数g()尝试为unique_ptr X调用那些相同的成员函数时,编译器突然想要一个完整的类型并尝试实例化X C,然后X C失败.由于某些原因,unique_ptr X :: get(
在下面的代码中,函数f()可以调用运算符bool()和operator *()的成员函数unique_ptr< C>对于不完整的类C,但是当函数g()尝试为unique_ptr< X>>调用那些相同的成员函数时,编译器突然想要一个完整的类型并尝试实例化X C,然后X C失败.由于某些原因,unique_ptr< X> :: get()不会导致模板实例化并正确编译,如在函数h()中可以看到的那样.这是为什么?什么使get()与运算符bool()和operator *()不同?
#include <memory>

class C;
std::unique_ptr<C> pC;

C& f() {
    if ( !pC ) throw 0; // OK,even though C is incomplete
    return *pC;         // OK,even though C is incomplete
}

template <class T>
class X
{
    T t;
};

std::unique_ptr<X<C>> pX;

X<C>& g() {
    if ( !pX ) throw 0; // Error: 'X<C>::t' uses undefined class 'C'
    return *pX;         // Error: 'X<C>::t' uses undefined class 'C'
}

X<C>& h() {
    if ( !pX.get() ) throw 0; // OK
    return *pX.get();         // OK
}

class C {};

解决方法

这里是一个设计简单的例子,仅使用我们自己的类型:
class Incomplete;

template <class T>
struct Wrap {
    T t;
};

template <class T>
struct Ptr {
    T* p;

    void foo() { }
};

template <class T>
void foo(Ptr<T> ) { }

int main() {
    Ptr<Incomplete>{}.foo();         // OK
    foo(Ptr<Incomplete>{});          // OK

    Ptr<Wrap<Incomplete>>{}.foo();   // OK
    ::foo(Ptr<Wrap<Incomplete>>{});  // OK!
    foo(Ptr<Wrap<Incomplete>>{});    // error
}

问题是,当我们对foo进行不合格的调用时,而不是对:: foo进行限定的调用,或者调用成员函数Ptr< T> :: foo(),我们触发参数相关的查找.

ADL将在类模板特殊化中查找模板类型的关联命名空间,这将触发隐式模板实例化.需要触发模板实例化以便执行ADL查找,因为例如Wrap< Incomplete>可以声明一个需要调用的朋友void foo(Ptr< Wrap< Incomplete>>).或包裹<不完整>可能有依赖基地,其名称空间也需要考虑.此时的实例化使得代码不正确,因为Incomplete是一个不完整的类型,并且您不能拥有不完整类型的成员.

回到原来的问题,对!pX和* pX的调用调用ADL,这导致X C的实例化.这是不正式的.对pX.get()的调用不会调用ADL,这就是为什么一个工作正常.

更多细节见this answer,也是CWG 557.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读