C++ 自定义范围类型 MSVC 编译但 G++ 不
C++ custom range type MSVC compiles but G++ doesn't
我正在使用 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++ 一起工作,我应该如何更改我的代码?谢谢
看来是MS VS的bug
特别是 range-based for 循环被转换为语句 like
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin )
也就是使用了声明
auto __begin = begin-expr, __end = end-expr;
但是您的函数 begin 和 end 具有不同的 return 类型。
FiboIterator begin() const {
return FiboIterator{};
}
int end() const {
return max;
}
因此您不能在此类声明中使用占位符说明符 auto
。
我同意@vlad-from-moscow,这可能是一个 MSVC 错误,因为 Visual Studio 2019 的默认设置是 C++14。它不应该编译。
你的代码自 c++17 以来都是正确的。
如果您使用 c++17,您的代码将在 GCC 和 CLang 上编译。
range-basedfor循环的实现发生了变化
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,那么您应该使 return 类型的开始和结束相同,以及 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};
}
};
我正在使用 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++ 一起工作,我应该如何更改我的代码?谢谢
看来是MS VS的bug
特别是 range-based for 循环被转换为语句 like
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin )
也就是使用了声明
auto __begin = begin-expr, __end = end-expr;
但是您的函数 begin 和 end 具有不同的 return 类型。
FiboIterator begin() const {
return FiboIterator{};
}
int end() const {
return max;
}
因此您不能在此类声明中使用占位符说明符 auto
。
我同意@vlad-from-moscow,这可能是一个 MSVC 错误,因为 Visual Studio 2019 的默认设置是 C++14。它不应该编译。
你的代码自 c++17 以来都是正确的。 如果您使用 c++17,您的代码将在 GCC 和 CLang 上编译。
range-basedfor循环的实现发生了变化
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,那么您应该使 return 类型的开始和结束相同,以及 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};
}
};