【问题标题】:Is it possible not to inherit from boost::operators, but still use it?是否可以不从 boost::operators 继承,但仍然使用它?
【发布时间】:2017-07-03 01:40:52
【问题描述】:

根据boost documentation - boost::operators 的正确用法是从中派生:

class A : boost::operators<A>
{
public:
    bool operator < (const A&) const { return false; }
};

现在,我可以使用&gt;&lt;=&gt;=,因为所有这些运算符都可以用&lt; 实现,请参见boost 中的代码sn-p:

template <class T, class B = operators_detail::empty_base<T> >
struct less_than_comparable1 : B
{
     friend bool operator>(const T& x, const T& y)  { return y < x; }
     friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); }
     friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }
};

最后less_than_comparable1boost::operators 基类之一。

问题: 但是添加这样的继承并不总是很方便。例如。这种继承意味着我必须向某些结构添加构造函数,否则所有旧代码,例如 A{1} 都会停止编译:

struct A : boost::operators<A>
{
    A() = default;
    A(int a, int b = 0) : a(a), b(b) {}
    int a;
    int b;
};
bool operator < (const A&, const A&);

我尝试了几种方法:内部类,boost::operators&lt;A&gt; 的静态成员,但似乎只有继承有效。


我接受一个答案,该答案显示了如何在没有继承的情况下使用 boost::operators。
我也可以接受一个答案,它解释了为什么需要这种继承。


好的,让我们稍微简化一下这个例子,为什么我需要在下面这个例子中继承才能从operator &lt; 获取operator &gt;

template <typename A>
struct GtOperator
{
    friend bool operator > (const A& l, const A& r)
    {
        return r < l;
    }
};

struct A : private GtOperator<A>
{
    bool operator < (const A&) const
    {
        return false;
    }
};

int main() {
    if (A{} > A{})
    {
        return -1;
    }
}

似乎没有其他工作,例如这种方式行不通:

struct A
{
    GtOperator<A> dummy;

    bool operator < (const A&) const
    {
        return false;
    }
};

【问题讨论】:

  • 要么手动写出来,要么写一个预处理器宏。 (只有六个运算符,无论如何你必须写operator &gt;。写operator == 通常也很有用。)
  • @MartinBonner boost::operators 提供的远不止这 3 个。我只想知道如果可能的话,如何在没有继承的情况下使用它。或者知道为什么需要继承
  • @jaggedSpire 在 boost::operators 中没有对子类的强制转换。来自less_than_comparable1 的只有这样的朋友运营商 - 没有向下转换。这就是为什么我要问为什么这里需要继承?

标签: c++ templates inheritance boost operators


【解决方案1】:

是否可以不继承boost::operators,但仍然使用它?

不,基本上。它的目的是继承自。它起作用的原因是,依赖于参数的查找只会在 关联类 ([basic.lookup.argdep]/4) 中查找友元函数和函数模板 - 这将是 AA 的基类。如果boost::operators&lt;A&gt; 不是A 的基类,则无法通过名称查找找到其friend 函数。

即使在 C++17 中使用新的聚合初始化规则,A{1,2} 也会中断,因为您必须编写 A{{},1,2}

您最好的选择可能是编写一个宏,该宏作为一个 mixin 可以有效地完成同样的事情。所以订购的将是:

#define LESS_THAN_COMPARABLE(T) \
 friend bool operator>(const T& x, const T& y)  { return y < x; } \
 friend bool operator<=(const T& x, const T& y) { return !static_cast<bool>(y < x); } \
 friend bool operator>=(const T& x, const T& y) { return !static_cast<bool>(x < y); }

class A
{
public:
    bool operator < (const A&) const { return false; }
    LESS_THAN_COMPARABLE(A)
};

是的,那很糟糕。 (这些也可以定义为非成员函数,只需删除 friend 并将宏调用放在类之外)。

另一种选择,除了添加构造函数和编写宏之外,是希望&lt;=&gt; 能够实现,然后等待几年才能使用它。

【讨论】:

  • 我怀疑我得到了这样的答案。但是我还是不知道为什么这里需要继承?为什么这样的构造不起作用struct A { bool operator&lt;(A)const; using dummy=boosts::operator&lt;A&gt;;};。在“经典”CRTP 中,模板参数类向下转换 - 在 boost::operators 中只有友元函数,根本没有向下转换
  • @PiotrNycz 添加了该解释。
  • 好的,我发现与您的回答平行的这个 wiki:en.wikipedia.org/wiki/Barton%E2%80%93Nackman_trickopen-std.org/jtc1/sc22/wg21/docs/papers/1995/N0777.pdf。所以答案是 ADL 仅适用于作为基类的友元注入的函数——这就是诀窍。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2018-08-26
  • 1970-01-01
  • 2013-11-22
  • 1970-01-01
  • 2023-04-10
相关资源
最近更新 更多