【问题标题】:C++ custom range type MSVC compiles but G++ doesn'tC++ 自定义范围类型 MSVC 可以编译,但 G++ 不能
【发布时间】:2020-08-03 12:10:55
【问题描述】:

我正在使用 Visual Studio 2019 来学习 C++,因为它是一个很棒的 IDE,可以当场发现错误。我下面的程序没有显示错误并且使用 MSVC 编译得很好,但是当我尝试使用 G++ 10.1 编译时它不会这样做

#include <cstdio>

class FiboIterator {
    int current{ 1 };
    int last{ 1 };
public:
    bool operator!=(int x) const {
        return x >= current;
    }
    FiboIterator& operator++() {
        const auto tmp = current;
        current += last;
        last = tmp;
        return *this;
    }
    int operator*() {
        return current;
    }
};

class FiboRange {
    const int max;
public:
    explicit FiboRange(int max): max{max} {}
    FiboIterator begin() const {
        return FiboIterator{};
    }
    int end() const {
        return max;
    }
};

int main() {
    for (const auto i : FiboRange{ 5000 }) {
        printf("%d ", i);
    }
}

g++ 输出以下消息:

main.cpp: In function 'int main()':
main.cpp:34:38: error: inconsistent begin/end types in range-based 'for' statement: 'FiboIterator' and 'int'
   34 |  for (const auto i : FiboRange{ 5000 }) {
      |                                      ^
main.cpp:34:38: error: conversion from 'int' to non-scalar type 'FiboIterator' requested
main.cpp:34:38: error: no match for 'operator!=' (operand types are 'FiboIterator' and 'FiboIterator')
main.cpp:7:7: note: candidate: 'bool FiboIterator::operator!=(int) const'
    7 |  bool operator!=(int x) const {
      |       ^~~~~~~~
main.cpp:7:22: note:   no known conversion for argument 1 from 'FiboIterator' to 'int'
    7 |  bool operator!=(int x) const {
      |                  ~~~~^

MSVC 和 G++ 之间有显着差异吗?如果我想让自定义范围适用于 G++,我应该如何更改我的代码?谢谢。

【问题讨论】:

  • 您是否向 gcc 提供了 -std=c++17 密钥?

标签: c++ visual-c++ compiler-errors g++


【解决方案1】:

我同意@vlad-from-moscow,这可能是一个 MSVC 错误,因为 Visual Studio 2019 的默认设置是 C++14。它不应该编译。

您的代码自 c++17 以来是正确的。 如果您使用 c++17,您的代码将在 GCC 和 CLang 上编译。

基于范围的for循环的实现发生了变化。

C++11:

{
   auto && __range = range_expression ; 
   for (auto __begin = begin_expr, __end = end_expr; 
       __begin != __end; ++__begin) { 
       range_declaration = *__begin; 
       loop_statement 
   }
} 

C++17:

{        
    auto && __range = range_expression ; 
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) { 
        range_declaration = *__begin; 
        loop_statement 
    } 
}

开始迭代器的类型为 FiboIterator,结束迭代器的类型为 int。

// c++11 version fails, auto can't deduce type
auto __begin = begin_expr, __end = end_expr; // an error here

// C++17 version works fine, they are different types.
auto __begin = begin_expr ;
auto __end = end_expr;

如果你不想使用 C++17,那么你应该让 begin 和 end 的返回类型和 FiboIterator 的比较运算符相同。

#include <cstdio>

class FiboIterator {
    int current{ 1 };
    int last{ 1 };
public:
    FiboIterator(int x=1) : current{x} {}

    bool operator!=(FiboIterator x) const {
        return x.current >= current;
    }
    FiboIterator& operator++() {
        const auto tmp = current;
        current += last;
        last = tmp;
        return *this;
    }
    int operator*() {
        return current;
    }
};

class FiboRange {
    const int max;
public:
    explicit FiboRange(int max): max{max} {}

    FiboIterator begin() const {
        return FiboIterator{};
    }
    FiboIterator end() const {
        return FiboIterator{max};
    }
};

【讨论】:

  • C++ 标准可能是您指出的问题。我确定 MSVC 使用的是 C++17,而我不确定我的 g++ 10.1 使用的是哪个标准,那么我该如何找到呢?如何将其设置为 C++17?我尝试了您的解决方案,效果很好。但是,原始代码是为了表明即使 begin()end() 返回类型不同,基于范围的 for 循环也可以工作,所以我猜是 C+ +17 是去这里的唯一途径
  • 您可以为其提供 -std=c++17 标志。默认为 14 或 11。
【解决方案2】:

好像是MS VS的bug。

特别是基于范围的 for 循环被转换为类似语句

for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin )

那就是使用了声明

auto __begin = begin-expr, __end = end-expr;

但是你的函数 begin 和 end 有不同的返回类型。

FiboIterator begin() const {
    return FiboIterator{};
}
int end() const {
    return max;
}

所以你不能在这样的声明中使用占位符说明符auto

【讨论】:

  • 其实这个程序的重点是展示基于范围的 for 循环如何在 begin()end() 的情况下仍然有效返回类型不同(因此使用 operator!=())。该代码来自一本 C++ 书籍,所以我不认为这是一个错误,它应该可以工作!也许 g++ 没有使用 C++17 标准?如前所述,我正在使用 g++ 10.1
猜你喜欢
  • 1970-01-01
  • 2021-05-23
  • 2012-04-30
  • 1970-01-01
  • 2023-03-21
  • 2017-02-27
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多