5

关于 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;
};
4

1 回答 1

3

在第一种情况下,不完整类型与std::unordered_map<K, Impl<K, T>: 一起使用的问题是,为了确定是什么iterator,部分需要在仅声明std::unordered_map<K, Impl<K, T>时实例化。Implstd::unique_ptr<...>错误无关。你可以去掉使用iter_typeas 的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被定义。

于 2013-08-24T23:18:20.123 回答