Bar*_*ett 10 c++ templates c++11
在下面的代码中,函数f()
可以调用operator bool()
和不完整的operator *()
成员函数.但是当函数试图调用那些相同的成员函数时,编译器突然想要一个完整的类型并尝试实例化,然后失败.由于某种原因,不会导致模板实例化并正确编译,如功能中所示.这是为什么?有什么不同和?unique_ptr<C>
class C
g()
unique_ptr<X<C>>
X<C>
unique_ptr<X<C>>::get()
h()
get()
operator 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 {};
Run Code Online (Sandbox Code Playgroud)
这是一个人为的简化示例,仅使用我们自己的类型:
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
}
Run Code Online (Sandbox Code Playgroud)
问题是,当我们进行非限定调用时foo
,而不是对::foo
成员函数的限定调用Ptr<T>::foo()
,我们将触发与参数相关的查找.
ADL将在类模板特化中查找模板类型的关联命名空间,这将触发隐式模板实例化.需要触发模板实例化以执行ADL查找,因为例如Wrap<Incomplete>
可以声明friend void foo(Ptr<Wrap<Incomplete >> )
需要调用的模板实例.或者Wrap<Incomplete>
可能有依赖基础,其名称空间也需要考虑.此时的实例化会使代码格式错误,因为它Incomplete
是一个不完整的类型,并且您不能拥有不完整类型的成员.
回到最初的问题,调用!pX
和*pX
调用ADL导致其瞬间X<C>
变形.调用pX.get()
并没有调用ADL,这就是为什么一个能正常工作.
这不是unique_ptr
需要完整类型,而是你的班级X
.
std::unique_ptr<C> pC;
Run Code Online (Sandbox Code Playgroud)
你实际上还没有进行任何分配,C
所以编译器不需要知道C
这里的具体细节.
std::unique_ptr<X<C>> pX;
Run Code Online (Sandbox Code Playgroud)
在这里,您将其C
用作模板类型X
.由于X
包含类型的对象,T
这是C
这里的编译器需要知道什么时候分配什么X
被实例化.(t
是一个对象,因此在构造时实例化).更改T t;
到T* t;
,编译器不会抱怨.
编辑:
这并不能解释h()编译的原因,但g()却没有.
这个例子很好编译:
#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;
typename std::add_lvalue_reference<X<C>>::type DoSomeStuff() // exact copy of operator*
{
return (*pX.get());
}
void g() {
if ((bool)pX) return;
}
class C {};
int main()
{
auto z = DoSomeStuff();
}
Run Code Online (Sandbox Code Playgroud)
这使得它更有趣,因为这模仿了operator*
,但不进行编译.!
从表达式中删除也有效.这似乎是多个实现中的错误(MSVC,GCC,Clang).
归档时间: |
|
查看次数: |
468 次 |
最近记录: |