You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否声明包含自身std::unordered_set成员的C++类?

问题描述

我想声明如下形式的类:

class A {
   std::unordered_set<A> set;
};

我知道需要为A实现哈希函数,但这不是核心问题。真正的问题是std::unordered_set的构造函数因A是不完全类型而报错,前向声明也无法解决这个问题,我不确定还有其他可行方案。

最小复现示例

class A;

template <>
struct std::hash<A> {
  // 仅声明,暂不定义,因A尚未定义
  size_t operator()( const A& ) const;
};

class A {
   public:
   bool operator==( const A& ) const { return true; }

   std::unordered_set<A> set;
};

inline size_t std::hash<A>::operator()( const A& ) const { return 0; }

编译错误信息(GCC 8.3.1,C++14)

/usr/include/c++/8/ext/aligned_buffer.h: In instantiation of struct __gnu_cxx::__aligned_buffer<A>:
/usr/include/c++/8/bits/hashtable_policy.h:234:43:   required from struct std::__detail::_Hash_node_value_base<A>
/usr/include/c++/8/bits/hashtable_policy.h:265:12:   required from struct std::__detail::_Hash_node<A, true>
/usr/include/c++/8/bits/hashtable_policy.h:2038:49:   required from struct std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<A, true>> >
/usr/include/c++/8/bits/hashtable.h:173:11:   required from class std::_Hashtable<A, A, std::allocator<A>, std::__detail::_Identity, std::equal_to<A>, std::hash<A>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, true, true> >
/usr/include/c++/8/bits/unordered_set.h:100:18:   required from class std::unordered_set<A>
/usr/include/c++/8/ext/aligned_buffer.h:91:28: error: invalid application of sizeof to incomplete type
 : std::aligned_storage<sizeof(_Tp), __alignof__(_Tp)>

除了使用unordered_set<A*>这类方案外,是否还有其他方法可以实现?


解决方案

除了指针方案,还有以下几种可行思路:

1. 用智能指针延迟容器实例化

把成员变量改为std::unique_ptr<std::unordered_set<A>>,这样在类A的定义阶段,std::unordered_set<A>不需要完全实例化——智能指针只依赖前向声明的类型。后续在构造函数中初始化智能指针,此时A已经是完整类型:

#include <memory>
#include <unordered_set>

class A;

template <>
struct std::hash<A> {
  size_t operator()(const A&) const;
};

class A {
public:
  bool operator==(const A&) const { return true; }
  std::unique_ptr<std::unordered_set<A>> set;

  A() : set(std::make_unique<std::unordered_set<A>>()) {}
};

inline size_t std::hash<A>::operator()(const A&) const { return 0; }

2. 封装自定义间接容器

自己实现一个轻量容器类,内部持有unordered_set<A>的指针,对外暴露和std::unordered_set一致的接口,隐藏间接层细节。本质和智能指针方案类似,但能让外部代码更自然地使用。

3. 升级编译器与C++标准(依赖实现)

部分编译器在C17及以后对部分容器放松了不完全类型的限制,比如GCC 10+允许std::vector使用不完全类型,但std::unordered_set的支持仍属于编译器扩展,并非标准强制要求。如果升级到更高版本GCC并启用C17或以上标准,可以尝试直接使用,但这种方式不保证跨编译器可移植。

4. 使用Boost容器库

boost::container::unordered_set明确支持不完全类型作为元素,只要在实际操作容器(如插入元素、调用成员函数)时A已经是完整类型即可。这种方案需要引入Boost依赖,但属于成熟可靠的第三方解决方案。


内容的提问来源于stack exchange,提问作者user1806566

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 21:15:18