Skip to content

Implement simple vector and tensor types#735

Open
Jullija wants to merge 22 commits intompusz:masterfrom
Jullija:feature/la-vectors
Open

Implement simple vector and tensor types#735
Jullija wants to merge 22 commits intompusz:masterfrom
Jullija:feature/la-vectors

Conversation

@Jullija
Copy link
Copy Markdown

@Jullija Jullija commented Oct 26, 2025

Added

Types

  • cartesian_vector — fixed 3D vector

Vector ops (a,b : cartesian_vector ; s : scalar)

  • a + b — elementwise addition
  • a - b — elementwise subtraction
  • a % b — elementwise modulo (% for integral, fmod for floating)
  • a * s, s * a — scalar multiply
  • a / s — scalar divide
  • a ⋅ b (scalar_product, alias dot) — dot product → scalar
  • a × b (vector_product, alias cross) — cross product → vector
  • |a| (magnitude, norm) — Euclidean length (floating reps only)
  • a/|a| (unit) — unit vector (floating reps only)

@Jullija Jullija changed the title Implement simple vector and tensor types [DRAFT] Implement simple vector and tensor types Oct 26, 2025
@Jullija Jullija marked this pull request as draft October 26, 2025 16:29
@Jullija Jullija force-pushed the feature/la-vectors branch from 20a6db0 to 7bc1e18 Compare October 26, 2025 16:33
Copy link
Copy Markdown
Owner

@mpusz mpusz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi!

Thanks for contributing! I had time to review only cartesian_vector changes and provided some feedback that I believe will also be meaningful to another type as well.

Comment on lines -25 to +26
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/requires_hosted.h>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We put requires_hosted.h as the first header in all HOSTED implementations. Do not use alphabetical order for this header.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still left to resolve.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this order, clang-format is failing

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you removed the comment below which was there to separate two header lists.

namespace mp_units {

MP_UNITS_EXPORT template<detail::Scalar T>
MP_UNITS_EXPORT template<detail::Scalar T = double>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to provide template defaults in the implementation rather than in one of (possibly many) forward declarations.

Comment on lines +57 to +58
requires requires(T t, U u) { t + u; }
requires requires(const T& t, const U& u) { t + u; }
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make any difference?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've read that adding const doesn't mutate an input which is desired in arithmetic operations (https://en.cppreference.com/w/cpp/language/operator_arithmetic.html)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right: https://godbolt.org/z/3zW8ns6YP. Thanks!

namespace detail {

struct cartesian_vector_iface {
// A + B
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such comments do not improve anything.

Comment on lines +76 to +95
// A % B (integral: %, floating: fmod into CT)
template<typename T, typename U>
requires requires(T t, U u) { t * u; }
[[nodiscard]] friend constexpr auto operator*(const cartesian_vector<T>& lhs, const U& rhs)
requires(requires(const T& t, const U& u) { t % u; }) || (std::floating_point<T> && std::floating_point<U>)
[[nodiscard]] friend constexpr auto operator%(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
{
using CT = std::common_type_t<T, U>;
if constexpr (std::floating_point<T> && std::floating_point<U>) {
using std::fmod;
return ::mp_units::cartesian_vector<CT>{static_cast<CT>(fmod(static_cast<long double>(lhs._coordinates_[0]),
static_cast<long double>(rhs._coordinates_[0]))),
static_cast<CT>(fmod(static_cast<long double>(lhs._coordinates_[1]),
static_cast<long double>(rhs._coordinates_[1]))),
static_cast<CT>(fmod(static_cast<long double>(lhs._coordinates_[2]),
static_cast<long double>(rhs._coordinates_[2])))};
} else {
return ::mp_units::cartesian_vector<CT>{static_cast<CT>(lhs._coordinates_[0] % rhs._coordinates_[0]),
static_cast<CT>(lhs._coordinates_[1] % rhs._coordinates_[1]),
static_cast<CT>(lhs._coordinates_[2] % rhs._coordinates_[2])};
}
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no op% for floating-point types for a reason. We should behave like fundamental types, so it should not be available as well for floating-point representation types. If we care about modulo for such types, we should provide fmod non-member function. See fmod from math.h for more info.

Comment on lines +288 to +333
template<typename FormatContext>
auto format(const mp_units::cartesian_vector<T>& vec, FormatContext& ctx) const
template<typename Ctx>
auto format(const mp_units::cartesian_vector<T>& v, Ctx& ctx) const
{
return format_to(ctx.out(), "[{}, {}, {}]", vec[0], vec[1], vec[2]);
return format_to(ctx.out(), "[{}, {}, {}]", v[0], v[1], v[2]);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please restore the previous code. FormatContext provides more info and is used consistently in the entire project for all formatters.

v is too short as an identifier and often causes some stupid shadowing errors in MSVC.

import mp_units;
#else
#include <mp-units/cartesian_vector.h>
#if MP_UNITS_HOSTED
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Runtime tests are only run for HOSTED so no need to check here.

Comment on lines +44 to +46
REQUIRE(v[0] == 0);
REQUIRE(v[1] == 0);
REQUIRE(v[2] == 0);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be garbage

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is why I didn't provide default construction.


SECTION("zero arguments")
{
cartesian_vector<double> v{};
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how zeros should be set, but this collides with your default-constructor now

using namespace Catch::Matchers;
using Catch::Matchers::WithinAbs;

TEST_CASE("cartesian_vector initialization and access", "[vector]")
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer to have fewer TEST_CASES in catch, so it is easier to manage. For example, if I want to check if all vector tests still work, it can check the status of one easy-to-find test rather than searching for many different strings.

Filtering by a tag is not often an option.

@Jullija
Copy link
Copy Markdown
Author

Jullija commented Oct 26, 2025

Hi! Thank you so much! I'll start reading and implementing changes - thank you and sorry in advance for any problems! :)

Comment on lines 149 to 173
cartesian_vector() = default;
cartesian_vector(const cartesian_vector&) = default;
cartesian_vector(cartesian_vector&&) = default;
cartesian_vector& operator=(const cartesian_vector&) = default;
cartesian_vector& operator=(cartesian_vector&&) = default;

template<typename... Args>
requires(... && std::constructible_from<T, Args>)
requires(sizeof...(Args) <= 3) && (... && std::constructible_from<T, Args>)
constexpr explicit(!(... && std::convertible_to<Args, T>)) cartesian_vector(Args&&... args) :
_coordinates_{static_cast<T>(std::forward<Args>(args))...}
{
}

template<typename U>
requires std::constructible_from<T, U>
requires std::constructible_from<T, const U&>
constexpr explicit(!std::convertible_to<U, T>) cartesian_vector(const cartesian_vector<U>& other) :
_coordinates_{static_cast<T>(other[0]), static_cast<T>(other[1]), static_cast<T>(other[2])}
{
}

template<typename U>
requires std::constructible_from<T, U>
requires std::constructible_from<T, U&&>
constexpr explicit(!std::convertible_to<U, T>) cartesian_vector(cartesian_vector<U>&& other) :
_coordinates_{static_cast<T>(std::move(other[0])), static_cast<T>(std::move(other[1])),
static_cast<T>(std::move(other[2]))}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove all of those. This will result in an aggregate type (such as std::array), which should solve all our issues. Please, change the comment next to a public member to reflect that.

@Jullija Jullija force-pushed the feature/la-vectors branch 9 times, most recently from f3f2391 to 00b2e74 Compare November 10, 2025 20:46
@Jullija
Copy link
Copy Markdown
Author

Jullija commented Nov 11, 2025

@mpusz could you help me fix the pipeline? I tried in some many ways and I have no idea how to fix it :c

@mpusz
Copy link
Copy Markdown
Owner

mpusz commented Nov 12, 2025

I am currently on vacation in Hawaii, so I don't have much time to look into it. I will check it out when I am back.

@Jullija Jullija force-pushed the feature/la-vectors branch 2 times, most recently from 1618ca3 to e564751 Compare November 20, 2025 18:41
@Jullija Jullija changed the title [DRAFT] Implement simple vector and tensor types Implement simple vector and tensor types Nov 20, 2025
@Jullija Jullija marked this pull request as ready for review November 20, 2025 19:21
@Jullija Jullija requested a review from mpusz November 20, 2025 19:38
Comment on lines -25 to +26
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/requires_hosted.h>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still left to resolve.

Comment on lines +157 to +164
MP_UNITS_EXPORT template<typename T, typename U>
requires requires(const T& t, const U& u) { t + u; }
[[nodiscard]] constexpr auto operator+(const cartesian_vector<T>& lhs, const cartesian_vector<U>& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] + rhs._coordinates_[0],
lhs._coordinates_[1] + rhs._coordinates_[1],
lhs._coordinates_[2] + rhs._coordinates_[2]};
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the operators and other customization points should be hidden friends as they were before.

{
cartesian_vector<double> v2 = v1;
cartesian_vector v1{1.0, 2.0, 3.0};
cartesian_vector<double> v2 = v1; // Use initialization instead of assignment
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an assignment

static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, cartesian_vector<double>>>);
static_assert(!std::convertible_to<quantity<one, double>, cartesian_vector<double>>);
static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>);
static_assert(std::is_aggregate_v<cartesian_vector<double>>);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes no sense and removes proper test

#else
#include <mp-units/cartesian_vector.h>
#include <mp-units/ext/format.h>
#include <sstream>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included twice

#endif

#ifndef MP_UNITS_MODULES
#include <sstream>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import std; missing.

Comment on lines +223 to +226
REQUIRE_THAT(u.magnitude(), WithinAbs(1.0, 1e-12));
REQUIRE_THAT(u[0], WithinAbs(3.0 / 5.0, 1e-12));
REQUIRE_THAT(u[1], WithinAbs(4.0 / 5.0, 1e-12));
REQUIRE_THAT(u[2], WithinAbs(0.0, 1e-12));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use AlmostEquals instead

}
}

TEST_CASE("cartesian_vector text output", "[vector][fmt][ostream]")
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove my tests that were testing each text output separately for different representation types?

@Jullija Jullija force-pushed the feature/la-vectors branch 2 times, most recently from 3d9fce9 to 69567bc Compare December 28, 2025 20:09
@Jullija Jullija requested a review from mpusz January 14, 2026 20:31
Comment on lines -25 to +26
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/requires_hosted.h>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you removed the comment below which was there to separate two header lists.

@Jullija Jullija force-pushed the feature/la-vectors branch 2 times, most recently from f69ccc8 to edcaf11 Compare January 21, 2026 07:58
@Jullija Jullija force-pushed the feature/la-vectors branch from edcaf11 to bfde546 Compare January 21, 2026 07:59
@Jullija Jullija force-pushed the feature/la-vectors branch from 9300ec9 to e82ac7d Compare January 22, 2026 20:48
@Jullija
Copy link
Copy Markdown
Author

Jullija commented Jan 22, 2026

In this discussion you mentioned to delete constructors to create an aggregate type. But after that I believe it is impossible to use static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>); 😅

Should I add this

  constexpr cartesian_vector() = default;
  explicit constexpr cartesian_vector(T x) : _coordinates_{x, T{}, T{}} {}
  constexpr cartesian_vector(T x, T y) : _coordinates_{x, y, T{}} {}
  constexpr cartesian_vector(T x, T y, T z) : _coordinates_{x, y, z} {}

or delete/modify this test? Or I misunderstood something?

@mpusz
Copy link
Copy Markdown
Owner

mpusz commented Jan 27, 2026

In this discussion you mentioned to delete constructors to create an aggregate type. But after that I believe it is impossible to use static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>); 😅

It is hard for me to judge without seeing the actual issue. Making this class an aggregate should not prevent this test from working. Unless I forgot about something now.

#include <mp-units/bits/module_macros.h>
#include <mp-units/framework/customization_points.h>
#include <mp-units/framework/representation_concepts.h>
#include <type_traits>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is not needed (included below). Also, this is not a correct section to include this file as it will collide with import std; if used.

Comment on lines -160 to -176
template<std::convertible_to<T> U>
constexpr cartesian_vector& operator=(const cartesian_vector<U>& other)
{
_coordinates_[0] = other[0];
_coordinates_[1] = other[1];
_coordinates_[2] = other[2];
return *this;
}

template<std::convertible_to<T> U>
constexpr cartesian_vector& operator=(cartesian_vector<U>&& other)
{
_coordinates_[0] = std::move(other[0]);
_coordinates_[1] = std::move(other[1]);
_coordinates_[2] = std::move(other[2]);
return *this;
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you delete those?

Comment on lines -201 to +101
return {-_coordinates_[0], -_coordinates_[1], -_coordinates_[2]};
return cartesian_vector{-_coordinates_[0], -_coordinates_[1], -_coordinates_[2]};
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be needed.

Comment on lines +164 to +245
template<typename U>
requires requires(const T& t, const U& u) { t + u; }
[[nodiscard]] friend constexpr auto operator+(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] + rhs._coordinates_[0],
lhs._coordinates_[1] + rhs._coordinates_[1],
lhs._coordinates_[2] + rhs._coordinates_[2]};
}

template<typename U>
requires requires(const T& t, const U& u) { t - u; }
[[nodiscard]] friend constexpr auto operator-(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
{
return ::mp_units::cartesian_vector{lhs._coordinates_[0] - rhs._coordinates_[0],
lhs._coordinates_[1] - rhs._coordinates_[1],
lhs._coordinates_[2] - rhs._coordinates_[2]};
}

template<typename U>
requires(!treat_as_floating_point<T> && !treat_as_floating_point<U> && requires(const T& t, const U& u) { t % u; })
[[nodiscard]] friend constexpr auto operator%(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
{
using CT = std::common_type_t<T, U>;
return ::mp_units::cartesian_vector<CT>{static_cast<CT>(lhs._coordinates_[0] % rhs._coordinates_[0]),
static_cast<CT>(lhs._coordinates_[1] % rhs._coordinates_[1]),
static_cast<CT>(lhs._coordinates_[2] % rhs._coordinates_[2])};
}

template<typename S>
requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && detail::NotQuantity<S>
[[nodiscard]] friend constexpr auto operator*(const cartesian_vector& vector, const S& scalar)
{
return ::mp_units::cartesian_vector{vector._coordinates_[0] * scalar, vector._coordinates_[1] * scalar,
vector._coordinates_[2] * scalar};
}

template<typename S>
requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && detail::NotQuantity<S>
[[nodiscard]] friend constexpr auto operator*(const S& scalar, const cartesian_vector& vector)
{
return vector * scalar;
}

template<typename S>
requires(!std::same_as<std::remove_cvref_t<S>, cartesian_vector>) && detail::NotQuantity<S>
[[nodiscard]] friend constexpr auto operator/(const cartesian_vector& vector, const S& scalar)
{
return ::mp_units::cartesian_vector{vector._coordinates_[0] / scalar, vector._coordinates_[1] / scalar,
vector._coordinates_[2] / scalar};
}

template<std::equality_comparable_with<T> U>
[[nodiscard]] friend constexpr bool operator==(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
{
return lhs._coordinates_[0] == rhs._coordinates_[0] && lhs._coordinates_[1] == rhs._coordinates_[1] &&
lhs._coordinates_[2] == rhs._coordinates_[2];
}

template<typename U>
requires requires(const T& t, const U& u, decltype(t * u) v) {
t * u;
v + v;
}
[[nodiscard]] friend constexpr auto scalar_product(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
{
return lhs._coordinates_[0] * rhs._coordinates_[0] + lhs._coordinates_[1] * rhs._coordinates_[1] +
lhs._coordinates_[2] * rhs._coordinates_[2];
}

template<typename U>
requires requires(const T& t, const U& u, decltype(t * u) v) {
t * u;
v - v;
}
[[nodiscard]] friend constexpr auto vector_product(const cartesian_vector& lhs, const cartesian_vector<U>& rhs)
{
return ::mp_units::cartesian_vector{
lhs._coordinates_[1] * rhs._coordinates_[2] - lhs._coordinates_[2] * rhs._coordinates_[1],
lhs._coordinates_[2] * rhs._coordinates_[0] - lhs._coordinates_[0] * rhs._coordinates_[2],
lhs._coordinates_[0] * rhs._coordinates_[1] - lhs._coordinates_[1] * rhs._coordinates_[0]};
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of those make the class template operations asymmetrical. RHS argument will not convert, while the LHS will. Please restore my cartesian_vector_iface to fix it -> both arguments will not convert. If you would like to enable conversion for the arguments, it is doable, but requires even more overloads.

Comment on lines +258 to +262
template<class T>
inline constexpr bool treat_as_floating_point<cartesian_vector<T>> = treat_as_floating_point<T>;

template<class S, class T>
inline constexpr bool is_value_preserving<S, cartesian_vector<T>> = is_value_preserving<S, T>;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +265 to +279
namespace std {
template<class T, class U>
struct common_type<mp_units::cartesian_vector<T>, mp_units::cartesian_vector<U>> {
using type = mp_units::cartesian_vector<common_type_t<T, U>>;
};

template<class T, class U>
struct common_type<mp_units::cartesian_vector<T>, U> {
using type = mp_units::cartesian_vector<common_type_t<T, U>>;
};

template<class T, class U>
struct common_type<U, mp_units::cartesian_vector<T>> {
using type = mp_units::cartesian_vector<common_type_t<U, T>>;
};
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it seems correct, but why did you have to do it? Was it required by some specific test?

Comment on lines -119 to 140
cartesian_vector v1{1.0, 2.0, 3.0};
cartesian_vector v2{4.0, 5.0, 6.0};
v1 += v2;
REQUIRE(v1[0] == 5.0);
REQUIRE(v1[1] == 7.0);
REQUIRE(v1[2] == 9.0);
}

SECTION("cartesian_vector compound assignment subtraction")
{
cartesian_vector v1{4.0, 5.0, 6.0};
cartesian_vector v2{1.0, 2.0, 3.0};
v1 -= v2;
REQUIRE(v1[0] == 3.0);
REQUIRE(v1[1] == 3.0);
REQUIRE(v1[2] == 3.0);
}

SECTION("cartesian_vector compound assignment scalar multiplication")
{
cartesian_vector v{1.0, 2.0, 3.0};
v *= 2.0;
REQUIRE(v[0] == 2.0);
REQUIRE(v[1] == 4.0);
REQUIRE(v[2] == 6.0);
}

SECTION("cartesian_vector compound assignment scalar division")
{
cartesian_vector v{2.0, 4.0, 6.0};
v /= 2.0;
REQUIRE(v[0] == 1.0);
REQUIRE(v[1] == 2.0);
REQUIRE(v[2] == 3.0);
SECTION("operator+=")
{
cartesian_vector v1{1.0, 2.0, 3.0};
cartesian_vector v2{4.0, 5.0, 6.0};
v1 += v2;
REQUIRE(v1[0] == 5.0);
REQUIRE(v1[1] == 7.0);
REQUIRE(v1[2] == 9.0);
}
SECTION("cartesian_vector compound assignment subtraction")
{
cartesian_vector v1{4.0, 5.0, 6.0};
cartesian_vector v2{1.0, 2.0, 3.0};
v1 -= v2;
REQUIRE(v1[0] == 3.0);
REQUIRE(v1[1] == 3.0);
REQUIRE(v1[2] == 3.0);
}
SECTION("cartesian_vector compound assignment scalar multiplication")
{
cartesian_vector v{1.0, 2.0, 3.0};
v *= 2.0;
REQUIRE(v[0] == 2.0);
REQUIRE(v[1] == 4.0);
REQUIRE(v[2] == 6.0);
}
SECTION("cartesian_vector compound assignment scalar division")
{
cartesian_vector v{2.0, 4.0, 6.0};
v /= 2.0;
REQUIRE(v[0] == 1.0);
REQUIRE(v[1] == 2.0);
REQUIRE(v[2] == 3.0);
}
}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to be formatted incorrectly, making it hard to compare. Please use pre-commit to format your files before commit (https://mpusz.github.io/mp-units/latest/getting_started/contributing/#unified-code-formatting).

Comment on lines -198 to +185
SECTION("cartesian_vector subtraction")
SECTION("cartesian_vector substraction")
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, cartesian_vector<double>>>);
static_assert(!std::convertible_to<quantity<one, double>, cartesian_vector<double>>);
static_assert(std::constructible_from<cartesian_vector<double>, quantity<one, double>>);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants