如何强制GCC警告使用类函数?

4
使用GCC 4.8.*时,当激活警告-Wfloat-equal时,编译器会警告关于浮点数之间的严格比较,就像下面的例子一样:
double x = 3.14159;
double y = 1.11111;
if(x == y) // <-- this induces a warning
{ /* ... */ }

现在,假设我想要一个包含双精度变量并定义等于运算符的类:
class Complex // (it's only an example)
{
  private:
    double re;
    double im;
  public:
    bool operator == (Complex const& z) const;
};
bool Complex::operator == (Complex const& z) const
{
  return (this->re == z.re) && (this->im == z.im);
}

这正是我所期望的。当然,在编译类时会产生一个警告。为了避免它(因为我理解编译器的警告,但我仍想这么做,并且不想继续看到警告),我通过以下方式通知编译器:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
bool Complex::operator == (Complex const& z) const
{
  return (this->re == z.re) && (this->im == z.im);
}
#pragma GCC diagnostic pop

好的,我没有在编译Complex.cpp文件时收到警告。但是,在复数上使用运算符==仍然是危险的,就像在双精度数字上使用运算符==一样(这是存在选项-Wfloat-equal的原因)。那么我的问题是: 是否可能有一个GCC警告(通过-Wfloat-equal激活),其中使用复数的运算符== 我想要警告的不是运算符的存在,而是其用法。 注意:我将对称运算符定义为类成员,但如果可以简化我的预期行为,则可以通过调用bool equals(...) const的类函数来调用bool operator == (Complex const&,Complex const&) 注意:出于兼容性原因,我不使用C++11。

能出现错误吗? - iBug
@iBug:我对一个报错的解决方案很感兴趣,但如果只是一个简单的警告就停止我的夜间构建,这将成为一个问题。 - Caduchon
我认为如果-Wfloat-equal能够过滤掉与精确浮点字面量(特别是0.0和1.0)进行比较的情况,它的实用性将会大大增强。 - Paul Floyd
2个回答

2
这似乎可以工作(在gcc4.8.5上实时演示):
__attribute__((warning ("your message")))
bool operator == (Complex const& z) const;

当然,您需要确保有问题的语句不会被优化掉...
目前,您需要手动禁用或启用它(通过某些定义)... 我不知道gcc是否允许检查警告是否已启用。

我认为不可能知道警告是否被激活。但是我使用CMake来管理构建,并通过CMake管理我的警告激活。很容易添加这种手工激活。 - Caduchon
这对我也起作用,但现在如果我知道当我比较复数时我在做什么,我就不能禁用此警告。:-p - Caduchon
1
你是对的;但是在这种情况下,你可以编写一个显式比较器a.exact_cmp(b),或者exact(a==b)。 - Massimiliano Janes
1
另一种选择是拥有两个非成员运算符==,非警告变体通过本地使用指示符激活... - Massimiliano Janes
嗯,有趣的解决方案。 - Caduchon

0

使用一个清晰表达意图的Exactly包装类型如何?

template<typename T>
struct Exactly : T
{
    explicit Exactly(T const& value) : T(value) {}
};

class Complex
{
    double re;
    double im;

public:
    Complex(double re, double im) : re(re), im(im) {}

    // Non-members require either friend access or public getters.
    double real() const { return re; }
    double imag() const { return im; }
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
bool operator == (Complex const& a, Exactly<Complex> const& b)
{
    return (a.real() == b.real()) && (a.imag() == b.imag());
}
// two more overloads for completeness
bool operator == (Exactly<Complex> const& a, Complex const& b)
{
    return (a.real() == b.real()) && (a.imag() == b.imag());
}
bool operator == (Exactly<Complex> const& a, Exactly<Complex> const& b)
{
    return (a.real() == b.real()) && (a.imag() == b.imag());
}
#pragma GCC diagnostic pop

你还可以像这样预定义常量(例如在本地或命名空间中):

Exactly<Complex> exactlyOne(Complex(1.0, 0.0));

并添加一个“maker”函数,这样您就不必重复类型名称,例如Complex

template<typename T>
Exactly<T> exactly(T const& value)
{
    return Exactly<T>(value);
}

operator != 留给读者练习。

小更新:如果你想允许 operator == 没有 Exactly,但是带有警告,则需要添加另一个重载 operator ==(Complex const& a, Complex const& b) 并使用 Massimiliano Janes 提到的属性。不过这似乎是不必要的。

演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接