std :: вектор известных последовательностей - PullRequest
0 голосов
/ 17 декабря 2009

Я пытаюсь выучить C ++, делая все "способом C ++". Я пишу программу, в которой у меня есть все эти известные значения (во время компиляции). Вот моя проблема:

В моем конструкторе я хочу проверить, является ли переданное значение (int) одним из 2,4,8,16 или 32, и в противном случае выдать ошибку. Я думаю о:

  1. создание массива в стиле C или целых чисел
  2. создавая вектор вручную и проверяя его, проверяя
  3. составление списка? Хотя я никогда не использовал списки раньше.

Что я действительно хочу сделать, так это создать константный вектор в отдельном заголовочном файле, хотя это кажется невозможным.

Какой самый элегантный способ сделать эту проверку?

Кроме того, есть ли способ сделать вектор с заданным числом известных значений (во время компиляции) в заголовке? Если я могу сделать const std::string a_str("a string");, я не понимаю, почему я не могу использовать подобную технику для векторов.

Ответы [ 6 ]

8 голосов
/ 17 декабря 2009

Что не так с:

if (!(n == 2 || n == 4 || n == 8 || n == 16 || n == 32))
{
    // no!
}

Если вы хотите "путь C ++", статический массив должен делать с find:

template <typename T, size_t N>
T* endof(T (&pArray)[N])
{
    return &pArray[0] + N;
}

static const int OkNumbers[] = {2, 4, 8, 16, 32};
static const int* OkNumbersEnd = endof(OkNumbers);
if (std::find(OkNumbers, OkNumbersEnd, n) == OkNumbersEnd)
{
    // no!
}

Изменить этот список просто, и я предполагаю, что компилятор может оптимизировать это для моего предыдущего ответа.

6 голосов
/ 17 декабря 2009

Это немного хитрость, но я считаю, что это работает:

if (n & (n-1) != 0)
{
   // not a power of two
}
2 голосов
/ 17 декабря 2009

Если мы говорим о немного глупой глупости, вот моя попытка:

if ((n & 0x3E) != n || (n & n - 1) != 0)
  throw std::runtime_error("not a power of two less than or equal to 32");

Глупость из-за переплетений битов - это ОЧЕНЬ C / C ++, но только «элегантный», если под элегантным вы подразумеваете «как можно меньше процессорных циклов и максимально краткий синтаксис». В противном случае используйте поиск по словарю или явную проверку (например, std :: find в ответе GMan).

Читаемость почти всегда предпочтительнее для этого вида дурачества.

1 голос
/ 17 декабря 2009

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

Но вы просто не хотите делать это с вектором;)

Редактировать: Я только что видел ваш "во время компиляции". Подумайте, почему этого нельзя сделать: std::vector не является встроенным типом. Чтобы иметь механизм для использования некоторого умного назначения, подобного этому, потребовалась бы встроенная поддержка для всего языка и каждого пользовательского типа. Даже если вам не нужна поддержка основного языка и вы можете сделать это с помощью шаблонов, это не будет соответствовать общему стилю STL.

0 голосов
/ 17 декабря 2009

Это может не соответствовать контексту того, что вы пытаетесь сделать, но вы можете использовать enum.

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

typedef enum 
{
  Value1 = 2,
  Value2 = 4,
  Value4 = 8,
  Value5 = 16,
  Value6 = 32

} MyMagicType;

void MyFunction(MyMagicType theType)
{
...
}

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

0 голосов
/ 17 декабря 2009

Используйте обычный массив C, мой C ржавый, но здесь идет

int array[] = {2,4,8,16,32};

/* now loop over the array and check */

for( i = 0; i< size_of_array ; i++) {
  if (array[i] == input_int) 
  /* you get the idea ..... */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...