стремясь создать собственный тип точки, написал следующее:
поэтому, прежде всего, используя концепцию для ограничения типа
//concept
template<typename T>
concept Numeric = requires(T param)
{
requires std::is_integral_v<T> || std::is_floating_point_v<T>;
requires !std::is_same_v<bool, T>;
requires std::is_arithmetic_v<decltype(param +1)>;
requires !std::is_pointer_v<T>;
};
базовый шаблон точки, просто оболочка вокруг массива
// Point<T,n>
template <Numeric T, size_t dim = 2 >
struct basic_point {
constexpr auto inline copy( basic_point<T,dim> const& p) {
std::copy(p, p + dim * sizeof(p[0]), array.begin());
}
auto inline copy( T const (&p)[dim]) {
std::copy(p, p + dim * sizeof(p[0]), array.begin());
}
auto inline copy( T const& val) noexcept {
for (auto& a : array)
a = val;
}
// new constructor
constexpr basic_point( T const (&pt)[dim]) { copy(pt); }
// copy constructor
constexpr basic_point( basic_point<T,dim> const& p) { copy(p); }
// default constructor
constexpr basic_point( T dt = 0 ) noexcept { copy(dt); }
virtual ~basic_point() = default ;
constexpr auto inline operator+=( basic_point<T,dim> const& o ) noexcept {
for(size_t i = 0; i < dim;i++)
array[i] += o.array[i];
}
constexpr auto inline operator-=( basic_point<T,dim> const& o ) noexcept { for(size_t i = 0; i < dim;i++) array[i] -= o.array[i]; }
friend constexpr inline auto operator+( basic_point<T,dim> const& a, basic_point<T,dim> const& b ) noexcept { basic_point<T,dim> sum{a}; sum += b; return sum; }
friend constexpr inline auto operator-( basic_point<T,dim> const& a, basic_point<T,dim> const& b ) noexcept { basic_point<T,dim> rest{a}; rest -= b; return rest;}
std::array<T,dim> array;
};
Затем специальный шаблон явно управляет 2d-точкой, где x и y относятся к элементам 0 и 1 массива, используя композицию, без наследования.
//Point2D<T>
template<Numeric T = size_t> struct Point2D {
constexpr Point2D(T const (&p)[2]) {
data = p;
x = data.array[0];
y = data.array[1];
}
Point2D(Point2D const& o) : x(o.x),y(o.y){}
void operator+=( Point2D const& other ) {
x += other.x;
y += other.y;
}
void operator-=( Point2D const& other) {
x -= other.x;
y -= other.y;
}
friend Point2D operator+( Point2D const& a, Point2D const& b ) {
Point2D sum( a );
sum += b;
return sum;
}
friend Point2D operator-( Point2D const&a, Point2D const& b ) {
Point2D rest( a );
rest -= b;
return rest;
}
T& x = data.array[0];
T& y = data.array[1];
basic_point<T,2> data = basic_point<T,2>(0);
};
чтобы проверить это, можно запустить тривиальный пример следующим образом
int main(int argc, char* argv[]) {
const int a[2] = { 1 , 3 };
const int b[2] = { 1 , 3 };
auto point_a = Point2D(a);
auto point_b = Point2D(b);
auto result = point_a + point_b;
std::cout << "Result : ("<< result.x << " , " << result.y <<")\n";
return 0;
}
но он компилируется и завершается из-за нарушения прав доступа. Есть идеи, почему это происходит.
тест можно посмотреть здесь
Кстати, пожалуйста, создайте с включенными дополнительными предупреждениями . А для будущих вопросов, пожалуйста, убедитесь, что у вас есть правильный, связный минимально воспроизводимый пример, чтобы мы могли просто скопировать и вставить.
Наличие ссылочных типов членов вызывает проблемы, вы не можете их повторно связать, и все сгенерированные компилятором операторы копирования/перемещения недействительны, а ваш определенный конструктор копирования неверен, поскольку он инициализирует ссылку, а не объект, на который ссылается.
x = data.array[0]; y = data.array[1];
в конструкторе делает не то, что вы думаете. x
и y
уже связаны, вы назначаете эти объекты себе.
Кажется, у вас есть довольно фундаментальные непонимания того, как работает C++. Какие ресурсы вы использовали для изучения основ C++? Возможно, вы захотите их обновить.
@Someprogrammerdude работает над этим ;)
@AhmedAEK Я не вижу другого способа получить доступ к значению из массива быстрее и удобнее для пользователя, чем point.x. и точка.й.
@Калет, извини, строки остались из предыдущей версии, где я пытался защитить массив...
вы можете определить функции доступа: T& x() { return data.array[0]; }
. Тогда Point2D
является регулярным. Это не медленнее, чем привязка ссылок как членов данных.
Я обнаружил, что удаление массива гораздо более удобно для пользователя, вам никогда не понадобится точка бесконечного размера, и люди склонны использовать x
гораздо чаще, чем data
, для любого 2D/3D API
предположим, что у меня есть облако точек из 1 миллиона точек, которыми я хочу манипулировать, используя массив даже для двух атрибутов x и y, заставить их склеиться в памяти, лучше, верно?
Вы неправильно выполнили арифметику указателей, когда вызывали std::copy
в своем методе basic_point::copy
, который принимает массив (T const (&p)[dim]
).
Вместо:
std::copy(p, p + dim * sizeof(p[0]), array.begin());
Должен быть:
std::copy(p, p + dim, array.begin());
Потому что когда вы используете operator+
для указателя (или массива), он автоматически учитывает sizeof
объекта, на который указывает указатель/массив, поэтому p + dim
уже продвигает адрес на dim
элементы размера sizeof(p[0])
.
Ошибка нарушения прав доступа, которую вы получаете, связана с тем, что вы обращаетесь к массиву за пределами границ (из-за неправильного конечного адреса).
Эта живая демонстрация представляет собой исправленную версию той, которую вы опубликовали: Live demo
Другая проблема, которая не вызвана вашим тестом, — это вызов std::copy
в другом basic_point::copy
(том, который принимает basic_point<T,dim> const& p
). Ваш код пытается использовать p
, как если бы это был указатель, но на самом деле это ссылка (на точку), поэтому это не имеет смысла.
Я не уверен, зачем вообще нужен этот метод, но, возможно, вы имели в виду что-то вроде:
std::copy(p.array.begin(), p.array.end(), array.begin());
Спасибо. теперь выглядит лучше демо
Рад был помочь. Кстати, в первой перегрузке copy
вы можете использовать p.array.end()
вместо p.array.begin() + dim
(это последняя строка в моем обновленном ответе).
Когда вы обнаруживаете сбой в своем отладчике, в каком месте вашего кода это происходит? Каковы значения всех задействованных переменных?