Избегайте копирования и вставки кода, инициализирующего серию SDL_Rects в структуре - PullRequest
2 голосов
/ 13 февраля 2012

У меня есть структура для определения графики объекта в моем 2D-движке.В этом есть ряд SDL_Rects, называемых «middle, left_edge, top_left_corner» и т. Д. В части моего кода я инициализирую их из ряда типов аргументов в механизм сценариев / командную строку, которые хранятся как векториз std :: strings.

Как стиль и избегая глупых ошибок из-за повторения (и необходимости исправлять ошибки 9 раз), есть ли способ очистить этот код?Или это будет разумно?

//RectZeroes is just an SDL_Rect of {0,0,0,0} to ensure that it is initialised

        SDL_Rect middle = RectZeroes;
        if (args.size() >= 6 ) 
        {
            middle.x = boost::lexical_cast<int>(args[3]); 
            middle.y = boost::lexical_cast<int>(args[4]);
            middle.w = boost::lexical_cast<int>(args[5]);
            middle.h = boost::lexical_cast<int>(args[6]);
        }

        SDL_Rect left_edge = RectZeroes;
        if (args.size() >= 10 ) 
        {
            left_edge.x = boost::lexical_cast<int>(args[7]); 
            left_edge.y = boost::lexical_cast<int>(args[8]);
            left_edge.w = boost::lexical_cast<int>(args[9]);
            left_edge.h = boost::lexical_cast<int>(args[10]);
        }
//And so on

1 Ответ

2 голосов
/ 13 февраля 2012

Я согласен, что это не приятный код.Чтобы избежать повторения, проделайте то же самое, что и всегда при программировании: encapsulate - в этом случае инкапсулируйте структуру и придав ей надлежащий конструктор, и напишите тонкую оболочку вокруг boost::lexical_cast<int>(x).

Или, если вы хотите избежать переноса SDL_Rect, напишите функцию инициализатора:

template <typename TString>
int parse_int(TString const& value) { return boost::lexical_cast<int>(value); }

void init_sdl_rect_from_args(
    SDL_Rect& rect, std::vector<std::string> const& args, unsigned offset)
{
    rect.x = parse_int(args[offset + 0]);
    rect.y = parse_int(args[offset + 1]);
    rect.w = parse_int(args[offset + 2]);
    rect.h = parse_int(args[offset + 3]);
}

А затем:

SDL_Rect middle = RectZeroes;
if (args.size() >= 6)
    init_sdl_rect_from_args(middle, args, 3);

SDL_Rect left_edge = RectZeroes;
if (args.size() >= 10)
    init_sdl_rect_from_args(left_edge, args, 7);

Еще лучше, сделайте инициализатор return построенная структура.Это делает его еще более удобным для использования (а именно в инициализаторе):

SDL_Rect rect_from_args(std::vector<std::string> const& args, unsigned offset) {
    SDL_Rect rect;
    rect.x = parse_int(args[offset + 0]);
    rect.y = parse_int(args[offset + 1]);
    rect.w = parse_int(args[offset + 2]);
    rect.h = parse_int(args[offset + 3]);
    return rect;
}

SDL_Rect middle = (args.size() >= 6) ? rect_from_args(args, 3) : RectZeroes;
SDL_Rect left_edge = (args.size() >= 10) ? rect_from_args(args, 7) : RectZeroes;
...