【问题标题】:Pedantic gcc warning: type qualifiers on function return typePedantic gcc 警告:函数返回类型的类型限定符
【发布时间】:2010-11-11 04:16:57
【问题描述】:

当我第一次使用 GCC 4.3 编译我的 C++ 代码时(在使用 -Wall -Wextra 选项成功编译它并且在 4.1、4.0、3.4 上没有任何警告之后)我突然收到一堆 @ 形式的错误987654323@.

考虑temp.cpp

class Something
{
public:
    const int getConstThing() const {
        return _cMyInt;
    }
    const int getNonconstThing() const {
        return _myInt;
    }

    const int& getConstReference() const {
        return _myInt;
    }
    int& getNonconstReference() {
        return _myInt;
    }

    void setInt(const int newValue) {
        _myInt = newValue;
    }

    Something() : _cMyInt( 3 ) {
        _myInt = 2;
    }
private:
    const int _cMyInt;
    int _myInt;
};

运行g++ temp.cpp -Wextra -c -o blah.o:

temp.cpp:4: warning: type qualifiers ignored on function return type
temp.cpp:7: warning: type qualifiers ignored on function return type

谁能告诉我我做错了什么违反了 C++ 标准?我想当按值返回时,前导 const 是多余的,但我无法理解为什么需要用它生成警告。还有其他地方我应该去掉 const 吗?

【问题讨论】:

  • 查看类似的问题和答案:stackoverflow.com/questions/1607188/…
  • 我以前看到过这样的警告,不过,我花了几分钟试图了解我的代码中发生了什么。可能更好的错误报告会加快速度。而不是warning: type qualifiers ignored on function return type 之类的warning: please don't add const qualifier when you are returning by value
  • @Avio 为什么我们不应该将const 限定符添加到返回值的函数中?我们这样做是因为我们不希望该值之后能够更改。
  • @Franky const int foo();

标签: c++ constants gcc-warning


【解决方案1】:

它不违反标准。这就是为什么它们是警告而不是错误

确实你是对的 - 领先的 const 是多余的。编译器会警告您,因为您添加了在其他情况下可能有意义的代码,但在这种情况下没有任何意义,并且它希望确保您稍后在返回值最终变成可修改时不会感到失望。

【讨论】:

  • 它警告而不是错误并不意味着什么。其他无效代码如sizeof(void) 也只是警告,但显然是禁止的。标准不知道警告和错误之间的区别:两者都是诊断。
  • @litb:他说的还是对的。当然,它们是警告这一事实并不能保证它不会像你说的那样违反标准,但是 reason 它们是警告而不是错误是编译器实现者不想禁止它。而他们不想禁止的原因是因为它不违反标准。
  • 完全违反标准吗?
  • 我认为我的第一句话很清楚,@Philipp。看问题评论中Johannes提到的问题:Why is a type qualifier on a return type meaningless?
【解决方案2】:

我在编译一些使用 Boost.ProgramOptions 的代码时遇到了这个警告。我使用-Werror,所以警告正在扼杀我的构建,但由于警告的来源在 Boost 的深处,我无法通过修改我的代码来摆脱它。

经过大量挖掘,我找到了禁用警告的编译器选项:

-Wno-ignored-qualifiers

希望这会有所帮助。

【讨论】:

  • 我遇到了同样的问题,最终将 Boost 的包含路径设置为 -isystem 而不是 -I,这会抑制 Boost 标头引发的所有警告。
  • @Philipp 的解决方案是正确的。使用 -Wno-ignored-qualifiers 会影响您的代码并阻止您的编译器发出您创建的警告,而 Philipp 的解决方案不会影响您自己的代码产生的警告。
【解决方案3】:

只有在返回引用或指针(在本例中是指向常量的指针而不是常量指针)时返回常量值才有意义,因为调用者能够修改引用(指向)的值。

对与您的问题无关的代码的另一条评论: 我认为最好使用 setter 而不是

int& getNonconstReference() {
    return _myInt;
}

应该是:

void setMyInt(int n) {
  _myInt = n;
}

此外,返回对 int 的 const 引用是没有用的。对于复制或移动成本更高的更大对象来说,这确实有意义。

【讨论】:

    【解决方案4】:

    有这个

    struct Foo { Foo(int) {} operator bool() { return true; } };

    还有那个

    Foo some_calculation(int a, int b) { Foo result(a + b); /*...*/ return result; }

    例子

    if (some_calculation(3, 20) = 40) { /*...*/ }

    编译时没有警告。当然,这种情况很少见。但是 const 的正确性难道不是让人们很难做错事吗?并且期望人们尝试错误的事情,返回类型应该声明为 const。 并且:g++ 警告忽略分类器,但不会忽略它。我认为,警告是关于获取副本并忽略其副本上的 const 分类器的用户。但这不应该是一个警告,因为这是绝对正确的行为。这样做是有意义的。

    【讨论】:

    • 如果您添加了const,G++ 不会在此处发出警告。 const 限定符仅对非类类型返回值被忽略。
    【解决方案5】:

    不应该 -pedantic 只允许严格遵守 ISO 标准吗?当然取决于 -std=...

    【讨论】:

      【解决方案6】:

      在声明函数返回指向不应修改的对象的指针时,此警告也有助于避免混淆:

      // "warning: type qualifiers ignored on function return type"
      // as the pointer is copied. 
      Foo* const bar();
      
      // correct:
      const Foo* bar();
      

      【讨论】:

        【解决方案7】:

        const 在基本类型结果上被忽略,const 在类类型结果上存在差异,它通常会造成严重破坏。

        namespace i {
            auto f() -> int const { return 42; }
            void g( int&& ) {}
        }
        
        namespace s {
            struct S {};
            auto f() -> S const { return {}; }
            auto g( S&&  ) {}
        }
        
        auto main() -> int
        {
            { using namespace i; g( f() ); }    // OK
            { using namespace s; g( f() ); }    // !The `const` prevents this.
        }
        

        这就是编译器在第一种情况下发出警告的原因:这是一种特殊情况,可能不会像人们天真地期望的那样。

        对于现代编程来说,恕我直言,在类类型结果上加上一个关于 const 的警告也会很好,因为它禁止移动语义;无论人们设想的任何一点优势,都要付出相当高昂的代价。

        【讨论】:

          【解决方案8】:

          Scott Meyers 指出有人想要返回 const 值是有充分理由的。这是一个例子:

          int some_calculation(int a, int b) { int res = 0; /* ... */ return res; }
          
          /* Test if the result of the calculation equals 40.*/
          if (some_calculation(3,20) = 40)
          {
          
          }
          

          你知道我做错了什么吗?这段代码绝对正确,应该可以编译。问题是编译器不明白您打算比较而不是分配40

          使用const 返回值时,上面的示例将无法编译。好吧,至少如果编译器不丢弃 const 关键字。

          【讨论】:

          • 不,它不应该编译。 some_calculation 的结果是一个 int 类型的右值。您不能分配给非类类型的右值。
          • 如果返回值是类类型,const是正确的,不会产生警告。
          • 你真的尝试过编译这个例子吗? GCC 给出“错误:需要左值作为赋值的左操作数”,clang++ 给出“错误:表达式不可赋值”
          • 他的意思可能是==
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-08-12
          • 2021-09-05
          • 2021-07-05
          • 2018-03-29
          • 2014-07-20
          • 2013-03-17
          • 2014-09-09
          相关资源
          最近更新 更多