Тип настраиваемого диапазона C ++ MSV C компилируется, а G ++ - нет - PullRequest
0 голосов
/ 03 августа 2020

Я использую Visual Studio 2019 для изучения C ++, потому что это отличная среда разработки, которая мгновенно обнаруживает ошибки. Моя программа ниже не показывает ошибок и отлично компилируется с использованием MSV C, но когда я попытался скомпилировать с 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 {
      |                  ~~~~^

Есть ли существенная разница между MSV C и G ++? Если я хочу, чтобы настраиваемый диапазон работал с G ++, как мне изменить свой код? Спасибо.

Ответы [ 2 ]

1 голос
/ 03 августа 2020

Я согласен с @ vlad-from-moscow, вероятно, это ошибка MSV C, потому что по умолчанию Visual Studio 2019 настроен на C ++ 14. Он не должен компилироваться.

Ваш код правильный, начиная с c ++ 17. Если вы используете C ++ 17, ваш код будет компилироваться на G CC и CLang.

Реализация на основе диапазона для l oop изменилась.

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};
    }
};
1 голос
/ 03 августа 2020

Похоже, это ошибка MS VS.

Основанный на диапазоне для l oop, в частности, конвертируется в оператор типа

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 в таком объявлении.

...