LoginSignup
0
0

More than 5 years have passed since last update.

数値管理クラス

Posted at

このクラス、実は元のコードが私が以前書いたこのコードなんです。
まあコードはこんなです。ちょっと色々オプション関数ありますけど…

Number.hpp
#ifndef __NUMBER_HPP__
#define __NUMBER_HPP__
#include <string>
#include <type_traits>
#include <limits>
#include <algorithm>
#include <cassert>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif

namespace standard {
#if _HAS_CXX17 == 0
    template<typename T, class Compare> constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp) {
        return  assert(!comp(hi, lo)),
            comp(v, lo) ? lo : comp(hi, v) ? hi : v;
    }
#endif
    template<class T> constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
#if _HAS_CXX17 == 0
        return standard::clamp(v, lo, hi, std::less<>());
#else
        return std::clamp(v, lo, hi);
#endif
    }

    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    class number {
    private:
        T n, maximum, minimum;
    protected:
        constexpr const T& cmp(const T num) {
            return clamp(num, this->minimum, this->maximum);
        }
    public:
        constexpr number() : number(0) {}
        constexpr number(const T& num, const T max, const T min) : n(clamp(num, min, max)), maximum(max), minimum(min) {}
        constexpr number(const T num) : number(num, std::numeric_limits<T>::max(), std::numeric_limits<T>::min()) {}
        constexpr number operator + (const number& num) const { return number(this->n + num.n, this->maximum, this->minimum); }
        constexpr number operator - (const number& num) const { return number(this->n - num.n, this->maximum, this->minimum); }
        constexpr number operator * (const number& num) const { return number(this->n * num.n, this->maximum, this->minimum); }
        constexpr number operator / (const number& num) const { 
            return num.n != 0
                ? number(this->n / num.n, this->maximum, this->minimum) 
                : throw std::runtime_error("Divide value is 0");
        }
        constexpr number operator & (const number& num) const { return number(this->n & num.n, this->maximum, this->minimum); }
        constexpr number operator % (const number& num) const {
            return num.n != 0
                ? number(this->n % num.n, this->maximum, this->minimum)
                : throw std::runtime_error("Divide value is 0"); 
        }
        constexpr number operator | (const number& num) const { return number(this->n | num.n, this->maximum, this->minimum); }
        constexpr number operator ^ (const number& num) const { return number(this->n ^ num.n, this->maximum, this->minimum); }
        constexpr number operator << (const number& num) const { return number(this->n << num.n, this->maximum, this->minimum); }
        constexpr number operator >> (const number& num) const { return number(this->n >> num.n, this->maximum, this->minimum); }
        number operator += (const number& num) { this->n = this->cmp(this->n + num.n); return *this; }
        number& operator ++ () { this->n = this->cmp(this->n + 1); return *this; }
        number operator ++ (int) { 
            const auto t = *this;
            this->n = this->cmp(this->n + 1); 
            return t;
        }
        number operator -= (const number& num) { this->n = this->cmp(this->n - num.n); return *this; }
        number& operator -- () { this->n = this->cmp(this->n - 1); return *this; }
        number operator -- (int) { 
            const auto t = *this;
            this->n = this->cmp(this->n - 1);
            return t;
        }
        number operator *= (const number& num) { this->n = this->cmp(this->n = num.n); return *this; }
        number operator /= (const number& num) { 
            if (num.n == 0) throw std::runtime_error("Divide value is 0");
            this->n = this->cmp(this->n = num.n); 
            return *this;
        }
        number operator &= (const number& num) { this->n = this->cmp(this->n & num.n); return *this; }
        number operator %= (const number& num) { 
            if (num.n == 0) throw std::runtime_error("Divide value is 0");
            this->n = this->cmp(this->n % num.n);
            return *this;
        }
        number operator |= (const number& num) { this->n = this->cmp(this->n | num.n); return *this; }
        number operator <<= (const number& num) { this->n = this->cmp(this->n << num.n); return *this; }
        number operator >>= (const number& num) { this->n = this->cmp(this->n >> num.n); return *this; }
        constexpr bool operator == (const number& num) const { return this->n == num.n; }
        constexpr bool operator != (const number& num) const { return this->n != num.n; }
        constexpr bool operator <  (const number& num) const { return this->n < num.n; }
        constexpr bool operator <= (const number& num) const { return this->n <= num.n; }
        constexpr bool operator >  (const number& num) const { return this->n > num.n; }
        constexpr bool operator >= (const number& num) const { return this->n >= num.n; }
        template<typename U, std::enable_if_t<std::is_arithmetic<U>::value, std::nullptr_t> = nullptr>
        operator number<U>() {
            return number<U>(
                this->n,
                this->maximum >= std::numeric_limits<U>::max() ? std::numeric_limits<U>::max() : this->maximum,
                this->minimum <= std::numeric_limits<U>::min() ? std::numeric_limits<U>::min() : this->minimum
                );
        }
        // 現在値を取得する
        template<typename U = T, std::enable_if_t<std::is_arithmetic<U>::value, std::nullptr_t> = nullptr>
        constexpr T Get() const noexcept { return static_cast<U>(this->n); }
        // 設定されている現在の最大値を取得する
        constexpr T GetMax() const noexcept { return this->maximum; }
        // 設定されている現在の最大値を取得する
        constexpr T GetMin() const noexcept { return this->minimum; }
        // 現在値を指定された値に変更する
        void ChangeCurrentNumToReserevedNum(const T num) { this->n = num; }
        // 最大値を指定された値に変更する
        // 例外 : 引数に指定された値が現在の最小値より小さい場合、std::runtime_errorが投げられる
        void ChangeMaximumToReservedNum(const T num) {
            if (num < this->minimum) throw std::runtime_error("maximum must be larger than minimum.");
            this->maximum = num;
            this->n = this->cmp(this->n);
        }
        // 最小値を指定された値に変更する
        // 例外 : 引数に指定された値が現在の最大値より大きい場合、std::runtime_errorが投げられる
        void ChangeMinimumToReservedNum(const T num) {
            if (num > this->maximum) throw std::runtime_error("minimum must be smaller than maximum.");
            this->minimum = num;
            this->n = this->cmp(this->n);
        }
        // 最大値に指定された値を加算する
        // 例外 : 引数に指定された値が負の場合、計算することによって最大値が最小値を下回る場合、std::runtime_errorが投げられる
        void AddToMax(const T num) { this->ChangeMaximumToReservedNum(this->GetMax() + num); }
        // 最大値に指定された値を加算する
        // 例外 : 引数に指定された値が正の場合、計算することによって最小値が最大値を上回る場合、std::runtime_errorが投げられる
        void AddToMin(const T num) { this->ChangeMinimumToReservedNum(this->GetMin() + num); }
    };
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const number<T>& v, const number<T>& lo, const number<T>& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const T& v, const number<T>& lo, const number<T>& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const number<T>& v, const T& lo, const number<T>& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const number<T>& v, const number<T>& lo, const T& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi)); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const T& v, const T& lo, const number<T>& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const T& v, const number<T>& lo, const T& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& clamp(const number<T>& v, const T& lo, const T& hi) { return number<T>(clamp<T>(v.Get(), lo.Get(), hi.Get())); }

    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator + (const T& n, const number<T>& num) { return number<T>(clamp(n + num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator - (const T& n, const number<T>& num) { return number<T>(clamp(n - num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator * (const T& n, const number<T>& num) { return number<T>(clamp(n * num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator / (const T& n, const number<T>& num) { return number<T>(clamp(n / num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator & (const T& n, const number<T>& num) { return number<T>(clamp(n & num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator % (const T& n, const number<T>& num) { return number<T>(clamp(n % num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator | (const T& n, const number<T>& num) { return number<T>(clamp(n | num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator ^ (const T& n, const number<T>& num) { return number<T>(clamp(n ^ num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator << (const T& n, const number<T>& num) { return number<T>(clamp(n << num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline number<T> operator >> (const T& n, const number<T>& num) { return number<T>(clamp(n >> num.Get(), num.GetMin(), num.GetMax()), num.GetMax(), num.GetMin()); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline bool operator == (const T& n, const number<T>& num) { return n == num.Get(); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline bool operator != (const T& n, const number<T>& num) { return n != num.Get(); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline bool operator <  (const T& n, const number<T>& num) { return n < num.Get(); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline bool operator <= (const T& n, const number<T>& num) { return n <= num.Get(); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline bool operator >  (const T& n, const number<T>& num) { return n > num.Get(); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    inline bool operator >= (const T& n, const number<T>& num) { return n >= num.Get(); }

    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& max(const number<T>& Left, const number<T>& Right) { return number<T>(std::max(Left.Get(), Right.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& max(const number<T>& Left, const T& Right) { return number<T>(std::max(Left.Get(), Right)); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& max(const T& Left, const number<T>& Right) { return number<T>(std::max(Left, Right.Get())); }

    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& min(const number<T>& Left, const number<T>& Right) { return number<T>(std::min(Left.Get(), Right.Get())); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& min(const number<T>& Left, const T& Right) { return number<T>(std::min(Left.Get(), Right)); }
    template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, std::nullptr_t> = nullptr>
    constexpr const number<T>& min(const T& Left, const number<T>& Right) { return number<T>(std::min(Left, Right.Get())); }

    inline number<long double> abs(const number<long double> n) { return number<long double>(std::abs(n.Get())); }
    inline number<double> abs(const number<double> n) { return number<double>(std::abs(n.Get())); }
    inline number<float> abs(const number<float> n) { return number<float>(std::abs(n.Get())); }
    inline number<long long> abs(const number<long long> n) { return number<long long>(std::abs(n.Get())); }
    inline number<long> abs(const number<long> n) { return number<long>(std::abs(n.Get())); }
    inline number<int> abs(const number<int> n) { return number<int>(std::abs(n.Get())); }

    namespace {
        template<typename T, std::enable_if_t<std::is_signed<T>::value, std::nullptr_t> = nullptr>
        number<T> string_to_signed_integer(const std::string& s, size_t* Index = 0, const int Base = 10) { return number<T>(static_cast<T>(std::stoll(s, Index, Base))); }
        template<typename T, std::enable_if_t<std::is_signed<T>::value, std::nullptr_t> = nullptr>
        number<T> wstring_to_signed_integer(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return number<T>(static_cast<T>(std::stoll(s, Index, Base))); }
        template<typename T, std::enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr>
        number<T> string_to_unsigned_integer(const std::string& s, size_t* Index = 0, const int Base = 10) { return number<T>(static_cast<T>(std::stoull(s, Index, Base))); }
        template<typename T, std::enable_if_t<std::is_unsigned<T>::value, std::nullptr_t> = nullptr>
        number<T> wstring_to_unsigned_integer(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return number<T>(static_cast<T>(std::stoull(s, Index, Base))); }
        template<typename T, std::enable_if_t<std::is_floating_point<T>::value, std::nullptr_t> = nullptr>
        number<T> string_to_float(const std::string s, size_t* Index = 0) { return number<T>(static_cast<T>(std::stold(s, Index))); }
        template<typename T, std::enable_if_t<std::is_floating_point<T>::value, std::nullptr_t> = nullptr>
        number<T> wstring_to_float(const std::wstring s, size_t* Index = 0) { return number<T>(static_cast<T>(std::stold(s, Index))); }
    }
    inline number<int> stoi(const std::string& s, size_t* Index = 0, const int Base = 10) { return string_to_signed_integer<int>(s, Index, Base); }
    inline number<int> stoi(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return wstring_to_signed_integer<int>(s, Index, Base); }
    inline number<long> stol(const std::string& s, size_t* Index = 0, const int Base = 10) { return string_to_signed_integer<long>(s, Index, Base); }
    inline number<long> stol(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return wstring_to_signed_integer<long>(s, Index, Base); }
    inline number<__int64> stoll(const std::string& s, size_t* Index = 0, const int Base = 10) { return string_to_signed_integer<__int64>(s, Index, Base); }
    inline number<__int64> stoll(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return wstring_to_signed_integer<__int64>(s, Index, Base); }
    inline number<unsigned int> stoui(const std::string& s, size_t* Index = 0, const int Base = 10) { return string_to_unsigned_integer<unsigned int>(s, Index, Base); }
    inline number<unsigned int> stoui(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return wstring_to_unsigned_integer<unsigned int>(s, Index, Base); }
    inline number<unsigned long> stoul(const std::string& s, size_t* Index = 0, const int Base = 10) { return string_to_unsigned_integer<unsigned long>(s, Index, Base); }
    inline number<unsigned long> stoul(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return wstring_to_unsigned_integer<unsigned long>(s, Index, Base); }
    inline number<unsigned __int64> stoull(const std::string& s, size_t* Index = 0, const int Base = 10) { return string_to_unsigned_integer<unsigned __int64>(s, Index, Base); }
    inline number<unsigned __int64> stoull(const std::wstring& s, size_t* Index = 0, const int Base = 10) { return wstring_to_unsigned_integer<unsigned __int64>(s, Index, Base); }
    inline number<float> stof(const std::string& s, size_t* Index = 0) { return string_to_float<float>(s, Index); }
    inline number<float> stof(const std::wstring& s, size_t* Index = 0) { return wstring_to_float<float>(s, Index); }
    inline number<double> stod(const std::string& s, size_t* Index = 0) { return string_to_float<double>(s, Index); }
    inline number<double> stod(const std::wstring& s, size_t* Index = 0) { return wstring_to_float<double>(s, Index); }
    inline number<long double> stold(const std::string& s, size_t* Index = 0) { return string_to_float<long double>(s, Index); }
    inline number<long double> stold(const std::wstring& s, size_t* Index = 0) { return wstring_to_float<long double>(s, Index); }
}
#endif

VSで動けばいいやなコードなのでGCCとかに持ってくとビルドエラーに…
で、これをpublic継承してmaxとminをtemplateに持ってきたのがこれです

Integer.hpp
#ifndef __INTEGER_HPP__
#define __INTEGER_HPP__
#include "Compassion.hpp"
#include "Number.hpp"

namespace standard {
    template<typename T, T max = std::numeric_limits<T>::max(), T min = std::numeric_limits<T>::min(), std::enable_if_t<std::is_integral<T>::value && compassion::e_large<T, max, min>, std::nullptr_t> = nullptr>
    class Integer : public number<T> {
    public:
        constexpr Integer() : number<T>() {}
        constexpr Integer(const T& num) : number<T>(num, max, min) {}
    };
}
#endif

Compassion.hppの中身はこの記事見てください
絶対private継承のほうがよかったよなと思ってます…

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0