C ++ основной вопрос конструктора - PullRequest
8 голосов
/ 08 июля 2010

Как мне справиться со следующей ситуацией:

Я пишу свой собственный класс векторного 2D и имею следующий код:

class Vector2 : public (...)
public:

   Vector2(float x, float y) {

      local_vector_storage_[0] = x;
      local_vector_storage_[1] = y;
   }

   template <typename Iterator> Vector2(Iterator begin, Iterator end) {

      ASSERT(end - begin == 2);

      resize(2);

      std::copy(begin, end, local_vector_storage_.begin());
   }

// ...
};

Теперь, если я скажуVector2 v(3.0f, 4.0f); он прекрасно компилируется и вызывает соответствующий конструктор float.

Но если я напишу Vector2 v(3, 4);, то это не получится, потому что шаблонный конструктор итератора «подходит лучше» и Vector2(Iterator(3), Iterator(4)).

Что мне делатьв этом случае?

Моя идея была о введении assign(It1, It2) метода члена вместо конструктора, но, может быть, есть лучшее решение?

Редактировать:

Кроме того, что вы думаете о ASSERT(end - begin == 2) линии?Я знаю, что это означает, что я не могу, например, передать итераторы std::list, но обеспечивает дополнительную безопасность.Должен ли я сделать это или нет?

Ответы [ 4 ]

6 голосов
/ 08 июля 2010

Кажется, что-то вроде этого работает:

template<typename T>
struct notnumeric {typedef int OK;};

template<>
struct notnumeric<int> {};

class Vector2
{
public:
   Vector2(float x, float y)
   {
   }

   template <typename Iterator>
   Vector2(Iterator begin, Iterator end, typename notnumeric<Iterator>::OK dummy = 0)
   {
   }
};

Я полагаю, что он использует SFINAE для предотвращения выбора компилятором второго ctor для нечисловых типов.

Что касается ASSERT (end - begin == 2), я думаю, вы должны использовать std::distance(begin, end) для определения расстояния между двумя итераторами.

1 голос
/ 08 июля 2010
1 голос
/ 08 июля 2010

В конкретном случае я не вижу смысла вводить Vector2(Iterator begin, Iterator end) c'or вообще.

В общем, я не вижу смысла имитировать std::vector (который по сути является оберткой для массива), когда размерность вашего Vector2 фиксирована и никогда не меняется. Перекрытие прецедентов между std::vector и вашим Vector2 незначительно для несуществующего: std::vector часто инициализируется из другого контейнера, тогда как Vector2 будет 50/50 инициализироваться двумя значениями или другим Vector2 .

И даже если вы решите пойти дальше, строка:

ASSERT(end - begin == 2);

резко ограничит полезность конструктора, так как относительно немного итераторов поддерживают арифметику.

1 голос
/ 08 июля 2010

РЕДАКТИРОВАТЬ: это 2d вектор?Или только два вектора?Я ответил на это для двумерного вектора.

Как мне справиться со следующей ситуацией

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

При чтении кода места вызова у меня не было бы никаких оснований полагать, что vector2 v2(1, 5); создает вектор из двух векторов, каждый с однимзначение.

Лично я бы ожидал, что он создаст матрицу 1x5.

Если это обычный случай использования вашей библиотеки, рассмотрим конструктор с именем :

vector2 Create2x1(float f1, float f2);

re: ASSERT

ASSERT - хорошая проверка работоспособности, но для поддержки Iterator требуется произвольный доступ (или хотя бы вычитание для поискарасстояние).Это может чрезмерно ограничить его использование.Попробуйте использовать std::distance или проверить, что local_vector_storage имеет размер два впоследствии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...