【问题标题】:Circular dependency with using directive where forward declarations don't work使用指令的循环依赖,其中前向声明不起作用
【发布时间】:2020-03-15 23:05:38
【问题描述】:

我正在使用无法解决这种循环依赖的代码库:

foo.h

class Foo
{
public:
  using Ptr = std::shared_ptr<Foo>;
  using ConstPtr = std::shared_ptr<const Foo>;

  void setter(const Bar::Ptr& bar_ptr) {};

private:
  Bar::WeakPtr bar_ptr_;
};

bar.h

class Bar
{
public:
  using Ptr = std::shared_ptr<Bar>;
  using ConstPtr = std::shared_ptr<const Bar>;
  using WeakPtr = std::weak_ptr<Bar>;

  Bar(Foo::ConstPtr foo_ptr) : foo_ptr_(std::move(foo_ptr)) {};

private:
  Foo::ConstPtr foo_ptr_;
};

它之前正在编译,因为有一个外部标头,其中:

using FooPtr = std::shared_ptr<Foo>;
using FooConstPtr = std::shared_ptr<const Foo>;
using BarPtr = std::shared_ptr<Bar>;

但由于追求一致性,我想要Foo::PtrFoo::ConstPtrBar::Ptr。我有机会得到它吗?

Coliru

编辑:添加了Bar::WeakPtr,因为我认为我已经遇到了麻烦,所以之前缺少它。

【问题讨论】:

  • 您能解释一下using 的要求并且不使用变量吗?
  • @cigien:不,这些不是嵌套的
  • @jackw11111 using 是为了隐藏它是std::shared_ptr 而不是boost::shared_ptr 的事实,有时很快。其实是using Ptr = my_namespace::shared_ptr&lt;Foo&gt;;
  • Foo 没有setter() 分配给的Bar::Ptr 成员,实际上setter() 根本不参与Bar 的共享所有权,所以它应该'根本不会使用shared_ptr&lt;Bar&gt;herbsutter.com/2013/06/05/…),因此您可以通过将Foo::setter() 更改为void setter(const Bar* bar_ptr) 来打破循环依赖关系,然后转发声明Bar
  • @RemyLebeau 你几乎是对的,我刚刚检查了Foo 有一个Bar::WeakPtr。我把例子简化了太多,让我修复它。

标签: c++ using circular-dependency forward-declaration


【解决方案1】:

这可以说是 C++ 的一个缺陷。你不能只声明一个类的一些公共名称而不包括整个类定义。在这种情况下,恐怕您的循环依赖无法解决 - 至少不会以某种方式在未来不会以某种方式影响您。

但是,作为替代方案,请考虑在主题类之外使用模板定义。它改变了术语的顺序,但不改变整体含义:

template<class T>
struct PtrStruct {
    using type = std::shared_ptr<T>;
};

template<class T>
using Ptr = typename PtrStruct<T>::type;

template<class T>
struct ConstPtrStruct {
    using type = std::shared_ptr<const T>;
};

template<class T>
using ConstPtr = typename PtrStruct<const T>::type;

在此设置中,您的Foo::Ptr 变为Ptr&lt;Foo&gt;Foo::ConstPtr 变为ConstPtr&lt;Foo&gt;。您仍然可以:

  • 稍后在定义PtrStruct 的单个位置将std::shared_ptr 替换为不同的东西。只要使用的接口没有改变,其余代码将无需更改即可编译。
  • 如果 PtrStruct 与其他 T 不同,则将其专门化。

【讨论】:

    【解决方案2】:

    如果追求一致性,请不要创建格式不正确的结构。您可以尝试以下方法:

    
    // Foo.h
    
    class Bar;
    
    class Foo
    {
    public:
      using BarPtr = std::shared_ptr<Bar>;
    
      void setter( BarPtr bar_ptr)
      {}
    };
    
    
    // Bar.h
    
    class Foo;
    
    class Bar
    {
    public:
      using ConstFooPtr=std::shared_ptr<const Foo>;
    
      Bar( ConstFooPtr foo_ptr)
          : foo_ptr_( std::move( foo_ptr))
      {}
    
    private:
      ConstFooPtr foo_ptr_;
    };
    
    

    【讨论】:

    • 你在类中交换了 PtrConstPtr
    • 在原始帖子中,bar.h 中似乎存在差异:构造函数将 shared_pointer 指向 const Foo 对象并尝试将 shared_ptr 存储到非 const Foo 对象。
    • @Andreas_75 已修复
    猜你喜欢
    • 1970-01-01
    • 2020-07-08
    • 2012-10-08
    • 2012-04-24
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多