Почему я получаю предупреждение о преобразовании Wsign? - PullRequest
0 голосов
/ 05 декабря 2018

У меня есть следующий код:

template <typename T>
struct wrapper {
    T t;
    operator T() { return t; }
    T get() { return t; }
};

int main() {
    int a[10];
    int* x = a;
    wrapper<long unsigned int> y{2};
    std::cout << (x + y); // warning
}

Когда я компилирую его на gcc (протестировано на 7.3.0 и 8.2.0) с -Wsign-conversion я получаю предупреждение: преобразование в long int из'long unsigned int' может изменить знак результата ".Если y имеет тип long unsigned int, предупреждение отсутствует.Более того, когда я явно вызываю y.get(), также не появляется предупреждение:

std::cout << (x + y.get()); // this is ok

Почему это так?Существуют ли специальные правила для арифметики указателей, которые нельзя использовать при использовании преобразования, определенного пользователем?

1 Ответ

0 голосов
/ 05 декабря 2018

Похоже на проблему с компилятором / ошибка

(спасибо @liliscent за исправление того, что я здесь говорил ранее)

Сначала давайте сделаем один MCVE для всех заявлений, которые вы упоминали:

#include <iostream>

template <typename T>
struct wrapper {
    T t;
    operator T() const { return t; }
    T get() const { return t; }
};

int main() {
    int a[10];
    int* x { a } ;
    wrapper<long int> y1{2};
    wrapper<unsigned int> y2{2};
    wrapper<long unsigned int> y3{2};

    std::cout << (x + y1) << '\n';
    std::cout << (x + y2) << '\n';
    std::cout << (x + y3) << '\n'; // this triggers a warning
    std::cout << (x + y3.get()) << '\n';
}

и, используя GCC 8.2.0, мы получаем :

<source>: In function 'int main()':
<source>:20:23: warning: conversion to 'long int' from 'long unsigned int' may change the sign of the result [-Wsign-conversion]
     std::cout << (x + y3) << '\n';
                       ^~
Compiler returned: 0

по ссылке,вы увидите, как:

  • GCC выдает эту ошибку со всеми (недавними) версиями.
  • Clang выдает эту ошибку с версией 6.0.
  • Clang делает not выдает эту ошибку с версией 7.0.

Так что это должен быть некоторый угловой случай с соответствием стандартам.

... но не входите в "Here Be Dragons""территория.

Теперь я уверен, что есть сложное техническое объяснение того, почему вы получаете ошибку только в 3-м из этих потоковых операторов.Но я утверждаю, что не имеет значения с точки зрения практического использования.Если вы будете только добавлять правильные целые числа в указатели - как вы делаете с оператором .get() - вы не получите это предупреждение.

Видите ли, вы пытаетесь добавить пользовательский тип вуказатель - который не имеет большого смысла вообще.Это правда, что ваша структура может быть преобразована в целое число, но полагаясь на то, что это преобразование будет выполнено неявно открывает вам такие вещи, как выбор преобразования другого операнда или другие пути преобразования, которые вы не рассматривали.Более того, это случаи, когда вы можете «нажать» на какое-то эзотерическое предложение в стандарте относительно того, когда неявные преобразования являются законными, что может или не может быть реализовано с абсолютной корректностью компилятором (см. Комментарий @ cppcleaner).

Так что просто используйте x + y3.get() в своем коде, и вам не придется беспокоиться об этих эзотерических угловых случаях.

Я приводил аналогичный аргумент в этом ответе относительно использованияиндекс 0 пустой строки (да, это так).

...