【问题标题】:Fix circular dependency in arithmetic class修复算术类中的循环依赖
【发布时间】:2015-07-24 15:23:06
【问题描述】:

我有一组实现奇怪重复的模板模式的类。然而,诀窍是基类需要返回子类的实例。这是一个例子:

template <typename SubType>
class ArithmeticBase
{
public:
    template <typename OtherType>
    const Addition operator+(const OtherType &other)
        {return Addition(get_subclass(), other);}

    // ...
    // Operators for subtraction, multiplication, division, ...

private:
    const SubType &get_subclass() const
        {return *static_cast<const SubType*>(this);}
};

template <typename OperatorType1, typename OperatorType2>
class Addition : ArithmeticBase<Addition<OperatorType1, OperatorType2>>
{
public:
    Addition(const OperatorType1 &op1, const OperatorType2 &op2)
        : op1(op1)
        , op2(op2)
    {}

private:
    const OperatorType1 &op1;
    const OperatorType2 &op2;
};

// ...
// Additional classes for subtraction, multiplication, division, ...

编译失败是因为Addition 类在用于ArithmeticBase 类之前没有定义:

arithmetic.cpp:6:8: error: unknown type name 'Addition'
        const Addition operator+(const OtherType &other)
              ^

我该如何解决这个问题?

【问题讨论】:

  • 非会员好友运营商?

标签: c++ templates c++11 circular-dependency crtp


【解决方案1】:

您可以在基类之前转发声明Addition

template <typename OperatorType1, typename OperatorType2>
class Addition;
template <typename SubType>
class ArithmeticBase
{
...
};

这允许编译器知道在定义之前存在一个类型Addition

【讨论】:

  • 这不是一个正确的类模板前向声明。
  • 谢谢,我没有意识到返回类型可能是不完整的类型。
  • @Joel:它可以在声明中,但不能在定义中。请参阅 JKor 的回答。
  • @BenVoigt 嗯,那为什么编译得很好? gist.github.com/anonymous/039e630dd66bc7d0eb43
  • @Joel:哦,对了,这是因为模板函数的实例化比函数模板定义发生的晚很多。
【解决方案2】:

或者使用Addition之后声明的非成员形式:

template <typename OperatorType1, typename OperatorType2>
class Addition;

template <typename SubType>
class ArithmeticBase
{
public:

     template <typename OneType, typename OtherType>
     friend const Addition<OneType, OtherType> operator+(const ArithmeticBase<OneType>& one, const OtherType &other);

private:
    const SubType &get_subclass() const
    {
        return *static_cast<const SubType*>(this);
    }
};

class ArithmeticType : public ArithmeticBase < ArithmeticType > {};

template <typename OperatorType1, typename OperatorType2>
class Addition : ArithmeticBase<Addition<OperatorType1, OperatorType2>>
{
public:
    Addition(const OperatorType1 &op1, const OperatorType2 &op2)
        : op1(op1)
        , op2(op2)
    {}

private:
    const OperatorType1 &op1;
    const OperatorType2 &op2;
};


template <typename OneType, typename OtherType>
const Addition<OneType, OtherType> operator+(const ArithmeticBase<OneType>& one, const OtherType &other)
{
    return Addition<OneType, OtherType>(one.get_subclass(), other);
}

int main()
{
    ArithmeticType a, b;
    a + b;
}

【讨论】:

  • 原版将左侧参数限制为ArithmeticBase的实例化,而您的则没有。
【解决方案3】:

除了转发声明 Addition 类(如 bhzag 的回答所示)之外,您还需要将 operator+ 的定义移到 Addition 类的定义之后。否则下一行会报错。

确保定义在头文件中。如果不是,您将收到链接器错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 2013-10-21
    • 2011-09-18
    • 2013-12-10
    • 1970-01-01
    相关资源
    最近更新 更多