Как должен я обрабатывать следующую ситуацию:
Я пишу свой собственный 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);
это компилирует прекрасный и вызывает соответствующего конструктора плавающего.
Но если я пишу Vector2 v(3, 4);
это перестало работать, потому что шаблонный конструктор итератора "соответствует лучше" и Vector2(Iterator(3), Iterator(4))
назван.
Что я должен сделать в этом случае?
Моя идея была о представлении assign(It1, It2)
членский метод вместо конструктора, но возможно существует лучшее решение?
Кроме того, о чем Вы думаете ASSERT(end - begin == 2)
строка? Я знаю, что это означает, что я не могу, например, передать итераторы std::list
, но приносит дополнительную безопасность. Я должен сделать это или нет?
Что-то вроде этого, кажется, работает:
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)
для определения расстояния между двумя итераторами.
Для разрешения вызова вот подробное почему от Herb Sutter
РЕДАКТИРОВАТЬ: Это 2-мерный вектор? Или всего два вектора? Я ответил на это для 2-мерного вектора.
Как мне поступить в следующей ситуации
Я думаю, вы должны справиться с ней, удалив конструктор float
. Из чтения кода непонятно, какой объект от этого следует ожидать.
Читая код callite, у меня не было бы оснований полагать, что vector2 v2 (1, 5);
создает вектор из двух векторов, каждый с одним значением.
Лично я ожидал, что он создаст матрицу 1x5
.
Если это типичный вариант использования вашей библиотеки, рассмотрите именованный конструктор :
vector2 Create2x1(float f1, float f2);
re: ASSERT
ASSERT - это хорошая проверка работоспособности, но требует вашего Iterator
для поддержки произвольного доступа (или, по крайней мере, вычитания для определения расстояния). Это может чрезмерно ограничить его использование. Рассмотрите возможность использования std :: distance
или проверки того, что local_vector_storage
имеет второй размер.
В конкретном случае я вообще не вижу смысла вводить Vector2 (Iterator begin, Iterator end)
c'tor.
В общем, я не вижу смысла имитировать std :: vector
(который по сути является оболочкой для массива), когда размер вашего Vector2
фиксирован и никогда не меняется . Перекрытие вариантов использования между std :: vector
и вашим Vector2
незначительно или отсутствует: std :: vector
часто инициализируется из другого контейнера, тогда как Vector2
будет инициализирован 50/50 двумя значениями или другим Vector2.
И даже если вы решите продолжить, строка:
ASSERT(end - begin == 2);
резко ограничит полезность конструктора, поскольку относительно небольшое количество итераторов поддерживают арифметику.