Sugestions на Макро Использование

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

Оригинальный код

...
namespace ConwaysGameOfLife
{
class Grid
{
private:
//Members
...
using set_of_ints  = std::unordered_set<int>;
using set_of_sizes = std::unordered_set<std::size_t>;
//Members to be used in Macros
set_of_sizes cells_at_t_minus_one;
set_of_sizes cells_at_t;
...
private:
//Functions
...
//Function showing Lengthy Conditionals
void rule(const std::size_t& cell_position)
{
std::size_t live_neighbors{0};

for(const auto& neighbor_offset : neighbor_offsets)
/*! Total Neighbors !*/
{
//Lengthy Conditional
if(cells_at_t_minus_one.find(cell_position + neighbor_offset) != cells_at_t.end())
{
live_neighbors++;
}
}
//Lengthy Conditional
if(cells_at_t_minus_one.find(cell_position) != cells_at_t.end() and live_neighbors < 2)
/*! Underpopulation !*/
{
cells_at_t.erase(cell_position);
}
//Lengthy Conditional
else if(cells_at_t_minus_one.find(cell_position) != cells_at_t.end() and (live_neighbors == 2 or live_neighbors == 3))
/*! Aging of a Cell !*/
{
cells_at_t.insert(cell_position);
}
//Lengthy Conditional
else if(cells_at_t_minus_one.find(cell_position) == cells_at_t.end() and live_neighbors == 3)
/*! Birth of a Cell !*/
{
cells_at_t.insert(cell_position);
}
//Lengthy Conditional
else if(cells_at_t_minus_one.find(cell_position) != cells_at_t.end() and live_neighbors > 3)
/*! Overpopulation !*/
{
cells_at_t.erase(cell_position);
}
}
public:
...
};
}
...

Код с макросами

...
#define neighbor cells_at_t_minus_one.find(cell_position + neighbor_offset)
#define cell cells_at_t_minus_one.find(cell_position)
#define dead cells_at_t.end()
#define is_live != dead
#define is_dead == dead
#define result second

namespace ConwaysGameOfLife
{
class Grid
{
private:
//Members
...
using set_of_ints  = std::unordered_set<int>;
using set_of_sizes = std::unordered_set<std::size_t>;
//Members used in Macros
set_of_sizes cells_at_t_minus_one;
set_of_sizes cells_at_t;
...
private:
//Functions
...
void rule(const std::size_t& cell_position)
{
std::size_t live_neighbors{0};

for(const auto& neighbor_offset : neighbor_offsets)
/*! Total Neighbors !*/
{
//Macros used
if(neighbor is_live)
{
live_neighbors++;
}
}
//Macros used
if(cell is_live and live_neighbors < 2)
/*! Underpopulation !*/
{
cells_at_t.erase(cell_position);
}
//Macros used
else if(cell is_live and (live_neighbors == 2 or live_neighbors == 3))
/*! Aging of a Cell !*/
{
cells_at_t.insert(cell_position);
}
//Macros used
else if(cell is_dead and live_neighbors == 3)
/*! Birth of a Cell !*/
{
cells_at_t.insert(cell_position);
}
//Macros used
else if(cell is_live and live_neighbors > 3)
/*! Overpopulation !*/
{
cells_at_t.erase(cell_position);
}
}
public:
...
};
}

#undef neighbor
#undef cell
#undef dead
#undef is_live
#undef is_dead
#undef result
...

0

Решение

Это:

if (neighbor is_live) { ... }

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

Это также приносит много проблем в таких вещах, как neighbor, dead, cell, result, а также is_live разумные имена для использования в качестве идентификаторов для этой конкретной программы. Так что, если вам случится использовать их в качестве идентификаторов, вы получите довольно непостижимые ошибки.

Рассмотрим альтернативу:

if (is_live(cell_position + neighbor_offset)) { ... }

где у нас просто есть функция is_live это только делает правильную вещь:

bool is_live(size_t idx) { return !cells_at_t_minus_one.count(idx); }

Это намного лучше, потому что:

  1. На самом деле это выглядит как синтаксически правильный код.
  2. Все переменные, которые мы используем, понятны и видны в коде.
  3. Я могу использовать любые идентификаторы, какие захочу, где угодно, и мне не нужно беспокоиться о том, что препроцессор их перезаписывает.
  4. Мои имена переменных не установлены в камне. Если я хочу изменить neighbor_offset просто быть offsetизменение имени влияет только на neighbor_offset (который в вашем коде даже не используется). Мне не нужно менять определение моего макроса!

Примечание: ваша проверка в реальном времени сравнивает итераторы из одного контейнера (cells_at_t_minus_one) с другим контейнером (cells_at_t).

1

Другие решения

Я решил использовать макросы, чтобы быть кратким и понятным.

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

Я бродил, если использование макросов, как это плохая практика.

Если под плохой практикой вы подразумеваете, что по мере роста и изменения вашей программы она станет неуправляемой, тогда да, это плохая практика.

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

В итоге…

не просто плохая практика, а самое худшее.

2

Мои эмпирические правила относительно макросов:

  1. Избегайте их использования, если можете. Вместо этого используйте встроенные функции или шаблоны, потому что макросы являются просто заменой текста и могут вызвать серьезные проблемы.

  2. Если вам нужно их использовать, назовите их очень четко. Попробуйте использовать имена, которые вряд ли появятся где-либо еще, потому что макросы — это просто замена текста.

Номер 2, чтобы избежать таких проблем, как:

#define equals ==
int main()
{
bool equals = 2 equals 3;
if( equals )
printf( "2==3 is true?" );
}

который заканчивается как:

int main()
{
bool == = 2 == 3;
if( == )
printf( "2==3 is true?" );
}

когда макрос будет обработан.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector