C++11:unique_ptr抱怨类型不完整,但当我包装它时却没有

C++11: unique_ptr complains about incomplete type, but not when I wrap it

本文关键字:包装 ptr unique 类型 C++11      更新时间:2023-10-16

关于SO上的unique_ptr和不完全类型,已经有很多问题了,但没有一个能给我一个概念来理解为什么以下不起作用:

// error: ... std::pair<...>::second has incomplete type
template<typename K, typename T> struct Impl {
    typedef typename std::unordered_map<K,Impl<K,T>>::iterator iter_type;
    std::unique_ptr<iter_type> ptr;
    Impl() : ptr(new iter_type()) {}
};
int main() { Impl<int,int>(); return 0; }

而以下情况会发生:

template<typename K, typename T> struct Impl {
  struct Wrapper {
    typedef typename std::unordered_map<K,Impl<K,T>>::iterator iter_type;
    iter_type iter;
  };
  std::unique_ptr<Wrapper> ptr;
  Impl() : ptr(new Wrapper()) {}
};
int main() { Impl<int,int>(); return 0; }

我看不出技术区别在哪里:如果第一个例子中std::pair<...>::second(即Impl<K,T>)对Impl不完整,那么第二个例子中它对Wrapper也应该不完整。而且当把unique_ptr封装在一个结构中就足够了,为什么对第一种情况有限制?

更新

在Dietmar Kühl的回答之后,我认为问题可以归结为以下几个方面:

template<typename K, typename T> struct Impl {
    typename std::unordered_map<K,Impl<K,T>>::iterator ptr;
};

template<typename K, typename T> struct Impl {
    struct Wrapper {
        typename std::unordered_map<K,Impl<K,T>>::iterator iter;
    };
    Wrapper *ptr;
};

第一种情况中的问题不完整类型与std::unordered_map<K, Impl<K, T>一起使用:要确定什么是iterator,需要在仅声明Impl时实例化std::unordered_map<K, Impl<K, T>的部分。std::unique_ptr<...>与错误无关。您可以删除对iter_type的使用,因为typedef需要验证它是否为类型。

另一方面,当将迭代器类型的使用包装到Wrapper中时,在构造函数实现之前不会使用此嵌套类型。当然,内联定义的函数的行为就好像类刚刚完全定义好,并且它们是在类定义之外实现的,也就是说,上面的代码相当于

template<typename K, typename T> struct Impl {
  struct Wrapper {
    typedef typename std::unordered_map<K,Impl<K,T>>::iterator iter_type;
    iter_type iter;
  };
  std::unique_ptr<Wrapper> ptr;
  Impl();
};
template<typename K, typename T>
Impl<K, T>::Impl() : ptr(new Impl<K, T>::Wrapper()) {}

也就是说,当需要并实例化Wrapper的定义时,定义Impl