(See the 2nd/previous iteration.)
I essentially removed all the type conversion trickery and have this:
numberbag.hpp
#ifndef CODERODDE_STAT_NUMBER_BAG
#define CODERODDE_STAT_NUMBER_BAG
#include <cmath>
#include <cstddef>
#include <iostream>
#include <initializer_list>
namespace coderodde {
namespace stat {
template<typename FloatingPoint = long double>
class number_bag final {
size_t m_size = 0;
FloatingPoint m_sum{};
FloatingPoint m_square_sum{};
public:
number_bag() = default;
number_bag(const number_bag& other) :
m_size{other.m_size},
m_sum{other.m_sum},
m_square_sum{other.m_square_sum}
{}
number_bag& operator=(const number_bag& other) {
m_size = other.m_size;
m_sum = other.m_sum;
m_square_sum = other.m_square_sum;
return *this;
}
number_bag(number_bag&& other) :
m_size{other.m_size},
m_sum{std::move(other.m_sum)},
m_square_sum{std::move(other.m_square_sum)}
{}
number_bag& operator=(number_bag&& other) {
m_size = other.m_size;
m_sum = std::move(other.m_sum);
m_square_sum = std::move(other.m_square_sum);
return *this;
}
number_bag(std::initializer_list<FloatingPoint> init_lst) {
for (auto fp : init_lst) {
add(fp);
}
}
void add(FloatingPoint num) noexcept {
++m_size;
m_sum += num;
m_square_sum += num * num;
}
void remove(FloatingPoint num) noexcept {
--m_size;
m_sum -= num;
m_square_sum -= num * num;
}
void clear() noexcept {
m_size = 0;
m_sum = FloatingPoint{};
m_square_sum = FloatingPoint{};
}
size_t size() const noexcept {
return m_size;
}
FloatingPoint average() const noexcept {
return m_sum / m_size;
}
FloatingPoint variance() const noexcept {
FloatingPoint step1 = m_square_sum - (m_sum * m_sum) / m_size;
return step1 / (m_size - 1);
}
FloatingPoint standard_deviation() const noexcept {
return std::sqrt(variance());
}
number_bag operator+(FloatingPoint fp) const noexcept {
number_bag ret(*this);
ret.add(fp);
return ret;
}
number_bag operator-(FloatingPoint fp) const noexcept {
number_bag ret(*this);
ret.remove(fp);
return ret;
}
number_bag& operator+=(FloatingPoint num) noexcept {
add(num);
return *this;
}
number_bag& operator-=(FloatingPoint num) noexcept {
remove(num);
return *this;
}
};
template<typename FloatingPoint>
auto operator+(FloatingPoint fp, number_bag<FloatingPoint>& bag) noexcept {
number_bag<FloatingPoint> ret(bag);
ret.add(fp);
return ret;
}
template<typename FloatingPoint>
auto operator-(FloatingPoint fp, number_bag<FloatingPoint>& bag) noexcept {
number_bag<FloatingPoint> ret(bag);
ret.remove(fp);
return ret;
}
template<typename Num>
std::ostream& operator<<(std::ostream& out, number_bag<Num> const &bag)
{
out << "[size=" << bag.size() << ", ave=" << bag.average() << ", var="
<< bag.variance() << ", std=" << bag.standard_deviation() << "]";
return out;
}
} // end of namespace coderodde::stat
} // end of namespace coderodde
#endif // CODERODDE_STAT_NUMBER_BAG
main.cpp
#include "numberbag.hpp"
#include <iostream>
int main() {
using coderodde::stat::number_bag;
using namespace std;
number_bag<float> bag;
bag.add(1.0);
bag.add(1.0);
bag.add(3.0);
cout << "bag: " << bag << '\n';
auto bag2 = bag - 1.0l;
cout << "bag: " << bag << '\n';
cout << "bag2: " << bag2 << '\n';
auto bag3 = 1.0f + bag2;
cout << "bag3: " << bag3 << '\n';
bag.clear();
cout << "bag: " << bag << '\n';
bag += 2.0f;
bag += 7.0f;
cout << "bag: " << bag << '\n';
bag2 = {1, 1, 3.0};
cout << "bag2: " << bag2 << '\n';
return 0;
}
Critique request
Please tell me about anything there is to improve.