Короткий и элегантный способ сделать типизацию в C ++? - PullRequest
0 голосов
/ 04 декабря 2018

Скажем, я хочу сохранить размер std::vector в int. Насколько мне известно, у меня есть следующие варианты:

int size = vector.size(); // Throws an implicit conversion warning
int size = (int)vector.size(); // C like typecasting is discouraged and forbidden in many code standards
int size = static_cast<int>(vector.size()); // This makes me want to gouge my eyes out (it's ugly)

Есть ли другие варианты, позволяющие избежать всего вышеперечисленного?вопросы?

Ответы [ 3 ]

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

Сохранение размера вектора, который может превышать максимальное значение int, в int - это в первую очередь уродливая операция.Это отражается в предупреждении вашего компилятора или в том факте, что вы должны написать некрасивый код для подавления предупреждения.

Наличие static_cast информирует других людей, читающих код, что здесь есть потенциальная ошибка, программа может работать со сбоями различными способами, если размер вектора превышает INT_MAX.

Очевидно (я надеюсь?) Лучшее решение - использовать правильный тип для хранимого значения: auto size = vector.size();.

Если вы действительно решили использовать int по любой причине, я бы порекомендовал добавить кодчтобы обработать регистр вектора, начните слишком большой (например, throw перед объявлением int, если оно есть) или добавьте комментарий кода, объясняющий, почему это никогда не было возможно.

Без комментариев читатель не может определить, было ли ваше приведение только потому, что вы хотели закрыть компилятор и не заботились о потенциальной ошибке;или если вы знали, что делаете.

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

Я собираюсь ответить на ваш вопрос так же, как вы спрашивали.Другие ответы говорят, почему вы не должны этого делать.Но если вы все еще хотите иметь это, используйте эту функцию:

#include <assert.h>
#include <limits.h>

inline int toInt(std::size_t value) {
    assert(value<=MAX_INT);
    return static_cast<int>(value);
}

Использование:

int size = toInt(vector.size());

toInt подтверждает, что вход value находится вне диапазона.Не стесняйтесь изменять его в соответствии с вашими потребностями.

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

Я собираюсь бросить вызов этому вопросу.Вы не должны хотеть короткого и элегантного решения этой проблемы.

Приведение на любом языке, включая C ++, в основном эквивалентно ругательству программиста: вы будете делать это иногда, потому что этолегко и без усилий, но не стоит.Это означает, что где-то ваш дизайн испортился.Возможно, вам нужно передать размер массива старому API, но старый API не использовал size_t.Возможно, вы разработали кусок кода для использования float, но в реальной реализации вы рассматриваете их как int.

В любом случае, приведение используется для исправления ошибок, допущенных в других местах кода. Вам не нужно короткое и простое решение, чтобы решить эту проблему .Вы должны предпочесть что-то явное и утомительное по двум причинам:

  • Это сигнализирует другим программистам, что приведение не является ошибкой: что-то преднамеренное и необходимое
  • Чтобы заставить васменьше шансов сделать это;и вместо этого сосредоточиться на том, чтобы убедиться, что ваши типы соответствуют вашим ожиданиям, а не ожидаемому целевому API.

Итак, примите static_cast, dynamic_cast, const_cast и reinterpret_cast стиль написания вашего кода.Вместо того, чтобы пытаться найти способы облегчить приведение типов, найдите способы рефакторинга вашего кода, чтобы они были менее необходимы.


Если вы готовы все это игнорировать, то напишите что-то вродеэто:

template<typename T, typename U>
T as(U && u) {
    return static_cast<T>(u);
}

int size = as<int>(values.size());

bool poly_type::operator==(base_type const& o) {
    if(this == &o)
        return true;
    if(typeid(*this) == typeid(o)) {
        return as<poly_type const&>(o).value == value;
    } else {
        return false;
     }
}

Это, по крайней мере, уменьшит количество набираемого текста.

...