1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
#include <iostream>
#include <fstream>
#include <string>
#include <functional>
struct Speed {
int speed = 0;
constexpr int getSpeed() const {return speed;}
explicit constexpr Speed (int s) : speed(s) {}
void dubble() {speed *= 2;}
};
struct Walks : Speed { explicit constexpr Walks( int w = 2 ) : Speed(w) {} ; };
struct Runs : Speed { explicit constexpr Runs( int r = 6 ) : Speed(r) {} ; };
struct Flies : Speed { explicit constexpr Flies( int f = 20 ) : Speed(f) {} ; };
struct Swims : Speed { explicit constexpr Swims( int s = 2) : Speed(s) {} ; };
template <typename...> class SpeedTypes;
template<typename...> struct DoubleSpeed;
template <typename FIRST, typename... REST>
struct DoubleSpeed<FIRST, REST...> {
void operator() (SpeedTypes<FIRST, REST...>* s) const {
s->FIRST::dubble();
DoubleSpeed<REST...>()(s);
}
};
template <>
struct DoubleSpeed<> {
void operator() (SpeedTypes<>*) const {}
};
template<typename...> struct SaveSpeed;
template <typename FIRST, typename... REST>
struct SaveSpeed<FIRST, REST...> {
void operator() (std::ostream& os, const SpeedTypes<FIRST, REST...>* s) const {
os << s->FIRST::getSpeed() << ' ';
SaveSpeed<REST...>()(os, s);
}
};
template <typename LAST>
struct SaveSpeed<LAST> {
void operator() (std::ostream& os, const SpeedTypes<LAST>* s) const {
os << s->LAST::getSpeed() << std::endl;
}
};
template<typename...> struct LoadSpeed;
template <typename FIRST, typename... REST>
struct LoadSpeed<FIRST, REST...> {
void operator() (std::istream& is, SpeedTypes<FIRST, REST...>* s) const {
is >> std::skipws >> s->FIRST::speed;
LoadSpeed<REST...>()(is, s);
}
};
template <>
struct LoadSpeed<> {
void operator() (std::istream&, SpeedTypes<>*) const {}
};
struct LivingBeing {
virtual ~LivingBeing() = default;
virtual int normal_speed() const = 0;
virtual void doubleSpeed() = 0;
virtual void saveSpeed (std::ostream&) const = 0;
virtual void loadSpeed (std::istream&) = 0;
// private:
// template <typename... T> friend SpeedTypes<T...>; // How to declare SpeedTypes<T...> friend so that below can be private?
template <typename... T> void doubleSpeedBase (SpeedTypes<T...>* s) {DoubleSpeed<T...>()(s);}
template <typename... T> void saveSpeedBase (std::ostream& os, const SpeedTypes<T...>* s) const {SaveSpeed<T...>()(os, s);}
template <typename... T> void loadSpeedBase (std::istream& is, SpeedTypes<T...>* s) const {LoadSpeed<T...>()(is, s);}
};
template <typename FIRST, typename... REST>
struct SpeedTypes<FIRST, REST...> : virtual public LivingBeing, virtual public FIRST, public SpeedTypes<REST...> {
virtual void doubleSpeed() override {doubleSpeedBase<FIRST, REST...>(this);} // The key overrides!
virtual void saveSpeed (std::ostream& os) const override {saveSpeedBase<FIRST, REST...>(os, this);}
virtual void loadSpeed (std::istream& is) override {loadSpeedBase<FIRST, REST...>(is, this);}
};
template <> struct SpeedTypes<> : virtual public LivingBeing {
virtual void doubleSpeed() override {} // LivingBeing that cannot move, so do nothing.
virtual void saveSpeed (std::ostream&) const override {}
virtual void loadSpeed (std::istream&) override {}
};
template < typename T > struct Usually : virtual LivingBeing, T {
Usually() = default ;
explicit Usually( int s ) : T(s) {} ;
virtual int normal_speed() const override { return T::getSpeed() ; }
};
template < typename T > using Only = Usually<T> ;
struct Human : SpeedTypes<Usually<Walks>, Runs, Swims> { Human() : Usually<Walks>(4), Runs(10), Swims(3) {} };
struct Cheetah : SpeedTypes<Usually<Runs>, Swims, Walks> { Cheetah() : Usually<Runs>(50), Swims(2), Walks(5) {} };
struct Bluejay : SpeedTypes<Usually<Flies>, Walks> { Bluejay() : Usually<Flies>(12), Walks(2) {} };
struct Trout : SpeedTypes<Only<Swims>> { Trout() : Only<Swims>(4) {} };
int main() {
Human human;
std::cout << human.normal_speed() << ' ' << human.Runs::getSpeed() << '\n';
Bluejay bluejay;
std::cout << bluejay.normal_speed() << ' ' << bluejay.Walks::getSpeed() << '\n';
Cheetah cheetah;
Trout trout;
std::reference_wrapper<const LivingBeing> animals[] = {human, bluejay, cheetah, trout};
for( const auto& w : animals ) std::cout << w.get().normal_speed() << ' ';
std::cout << "\n---------------\n\n";
std::cout << human.Walks::getSpeed() << ' ' << human.Runs::getSpeed() << ' ' << human.Swims::getSpeed() << '\n';
human.doubleSpeed();
std::cout << "After doubling speeds:\n";
std::cout << human.Walks::getSpeed() << ' ' << human.Runs::getSpeed() << ' ' << human.Swims::getSpeed() << '\n';
const std::string path = "human.txt";
std::ofstream outfile (path);
human.saveSpeed(outfile);
std::cout << "File contains: " << std::ifstream(path).rdbuf();
std::ifstream infile (path);
Human h;
h.loadSpeed(infile);
std::cout << h.Walks::getSpeed() << ' ' << h.Runs::getSpeed() << ' ' << h.Swims::getSpeed() << '\n';
}
|