【问题标题】:How to force GCC to warn about usage of a class function?如何强制 GCC 警告类函数的使用?
【发布时间】:2018-05-01 02:11:42
【问题描述】:

使用 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 operator == (Complex const&amp;,Complex const&amp;) 调用的类函数 bool equals(...) const

注意:出于兼容性原因,我不使用 C++11。

【问题讨论】:

  • 会是错误吗?
  • @iBug:我对给出错误的解决方案很感兴趣,但如果一个简单的警告阻止它们,这对我的夜间构建来说是个问题。
  • 我认为,如果 -Wfloat-equal 可以过滤掉与精确浮点字面量的比较,特别是 0.0 和 1.0,那么它的实用性会大大增强。

标签: c++ gcc c++03 pragma gcc-warning


【解决方案1】:

如何使用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 != 留给读者作为练习。

次要更新:如果您想在没有Exactly 的情况下允许operator ==,但带有警告,那么您需要添加另一个重载operator ==(Complex const&amp; a, Complex const&amp; b),并具有Massimiliano Janes 提到的属性。不过好像没必要。

Demo

【讨论】:

    【解决方案2】:

    这似乎有效 (live on gcc4.8.5):

    __attribute__((warning ("your message")))
    bool operator == (Complex const& z) const;
    

    当然,你需要确保有问题的语句没有被优化出来..

    事实上,您需要手动禁用/启用它(通过一些定义)...我不知道 gcc 是否允许检查警告是否已启用。

    【讨论】:

    • 我认为不可能知道是否激活了警告。但是我使用 CMake 来管理构建,并通过 CMake 管理我的警告激活。添加这种手工激活很容易。
    • 这也适用于我,但现在如果我知道在比较复数时我会做什么,我就无法禁用此警告。 :-p
    • 你是对的;但在这种情况下,您可以编写一个显式比较器 a.exact_cmp(b) 或 exact(a==b)
    • 另一种选择是有两个非成员 operator==,通过本地 using 指令激活非警告变体...
    • 嗯,有趣的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 2017-07-25
    • 2019-04-30
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多