Solution: Vector Algebra
Learn about the solution to the vector algebra challenge in this lesson.
We'll cover the following...
Vector algebra using expression templates
Let’s execute the provided solution for the vector algebra challenge and observe the code output. Subsequently, we’ll dissect the code step by step.
Press + to interact
#include <iostream>#include <vector>#include <stdexcept>#include <concepts>template<typename T, typename C = std::vector<T>>requires std::is_arithmetic_v<T>struct vector {vector() = default;vector(std::size_t const n) : data_(n) {}vector(std::initializer_list<T>&& l) : data_(l) {}vector(C const& other) : data_(other) {}template<typename U, typename X>vector(vector<U, X> const& other) : data_(other.size()) {for (std::size_t i = 0; i < other.size(); ++i)data_[i] = static_cast<T>(other[i]);}template<typename U, typename X>vector& operator=(vector<U, X> const& other) {data_.resize(other.size());for (std::size_t i = 0; i < other.size(); ++i)data_[i] = static_cast<T>(other[i]);return *this;}std::size_t size() const noexcept {return data_.size();}T operator[](const std::size_t i) const {return data_[i];}T& operator[](const std::size_t i) {return data_[i];}C& data() noexcept { return data_; }C const& data() const noexcept { return data_; }private:C data_;};template<typename L, typename R>struct vector_add {vector_add(L const& a, R const& b) : lhv(a), rhv(b){if (a.size() != b.size()) {throw std::runtime_error("The vector size is incompatible for this operation.");}}auto operator[](std::size_t const i) const {return lhv[i] + rhv[i];}std::size_t size() const noexcept {return lhv.size();}private:L const& lhv;R const& rhv;};template<typename L, typename R>struct vector_sub {vector_sub(L const& a, R const& b) : lhv(a), rhv(b){if (a.size() != b.size()) {throw std::runtime_error("The vector size is incompatible for this operation.");}}auto operator[](std::size_t const i) const {return lhv[i] - rhv[i];}std::size_t size() const noexcept {return lhv.size();}private:L const& lhv;R const& rhv;};template<typename L, typename R>struct vector_mul {vector_mul(L const& a, R const& b) : lhv(a), rhv(b){if (a.size() != b.size()) {throw std::runtime_error("The vector size is incompatible for this operation.");}}auto operator[](std::size_t const i) const {return lhv[i] * rhv[i];}std::size_t size() const noexcept {return lhv.size();}private:L const& lhv;R const& rhv;};template<typename S, typename R>struct vector_scalar_mul {vector_scalar_mul(S const& s, R const& b) :scalar(s), rhv(b) {}auto operator[](std::size_t const i) const {return scalar * rhv[i];}std::size_t size() const noexcept {return rhv.size();}private:S const& scalar;R const& rhv;};// Calculate the dot product between two vectorstemplate<typename T, typename L, typename U, typename R>auto dot(vector<T, L> const& a, vector<U, R> const& b){if (a.size() != b.size()) {throw std::runtime_error("The vector size is incompatible for this operation.");}using result_type = decltype(std::declval<T>() * std::declval<U>());result_type result = 0;for (std::size_t i = 0; i < a.size(); ++i)result += a[i] * static_cast<T>(b[i]);return result;}// Overloaded operator+ for element-wise additiontemplate<typename T, typename L, typename U, typename R>auto operator+(vector<T, L> const& a, vector<U, R> const& b) {using result_type = decltype(std::declval<T>() + std::declval<U>());return vector<result_type, vector_add<L, R>>(vector_add<L, R>(a.data(), b.data()));}// Overloaded operator- for element-wise subtractiontemplate<typename T, typename L, typename U, typename R>auto operator-(vector<T, L> const& a, vector<U, R> const& b){using result_type = decltype(std::declval<T>() - std::declval<U>());return vector<result_type, vector_sub<L, R>>(vector_sub<L, R>(a.data(), b.data()));}// Overloaded operator* for element-wise multiplicationtemplate<typename T, typename L, typename U, typename R>auto operator*(vector<T, L> const& a, vector<U, R> const& b) {using result_type = decltype(std::declval<T>() + std::declval<U>());return vector<result_type, vector_mul<L, R>>(vector_mul<L, R>(a.data(), b.data()));}// Overloaded operator* for scalar multiplicationtemplate<typename T, typename S, typename E>auto operator*(S const& a, vector<T, E> const& v) {using result_type = decltype(std::declval<T>() + std::declval<S>());return vector<result_type, vector_scalar_mul<S, E>>(vector_scalar_mul<S, E>(a, v.data()));}// Overloaded stream operator for printing vector elementstemplate<typename V>std::ostream& operator<<(std::ostream& os, const vector<V> v) {os << "{";for (std::size_t i = 0; i < v.size(); ++i) {os << v[i];if (i < v.size() - 1) {os << ", ";}}os << "}";return os;}int main() {vector<int> v1{1, 2, 3, 4};vector<int> v2{5, 6, 7, 8};double a{1.5};try {// Perform vector operationsvector<double> v3 = v1 + a * v2; // {8.5 11 13.5 16}vector<int> v4 = v1 * v2 + v1 + v2; // {11 20 31 44}vector<double> v5 = v1 * v2 - v1 + a * v2; // {11.5 19 28.5 40}int dot_result = dot(v1, v2); // {70}// Output the resultsstd::cout << "v3 = " << v3 << std::endl;std::cout << "v4 = " << v4 << std::endl;std::cout << "v5 = " << v5 << std::endl;std::cout << "dot_result = " << dot_result << std::endl;} catch (const std::runtime_error& e) {std::cerr << "Error: " << e.what() << std::endl;}return 0;}
...