Created
May 17, 2014 16:55
-
-
Save Fiona-J-W/e91a8aeda78c5e040299 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cassert> | |
#include <iostream> | |
enum class side { | |
good, | |
evil | |
}; | |
enum class strength { | |
strong, | |
weak | |
}; | |
template<side Side, strength Strength> | |
class warrior { | |
public: | |
void attack() const; | |
void heal() const; | |
void flee() const; | |
void plunder() const; | |
template<typename...Args> | |
double insane_method(Args&&...) const { | |
std::cout << "Ignore ALL the arguments!\n"; | |
return 1.0; | |
} | |
void nonconst_method() {std::cout << "nonconst method!\n";} | |
}; | |
template<side Side, strength Strength> | |
void warrior<Side, Strength>::attack() const { | |
std::cout << "The strong warrior attacks!\n"; | |
} | |
template<> void warrior<side::good, strength::weak>::attack() const = delete; | |
template<> void warrior<side::evil, strength::weak>::attack() const = delete; | |
template<side Side, strength Strength> | |
void warrior<Side, Strength>::heal() const { | |
std::cout << "The good warrior heals!\n"; | |
} | |
template<> void warrior<side::evil, strength::strong>::heal() const = delete; | |
template<> void warrior<side::evil, strength::weak>::heal() const = delete; | |
template<side Side, strength Strength> | |
void warrior<Side, Strength>::plunder() const { | |
std::cout << "The evil warrior plunders!\n"; | |
} | |
template<> void warrior<side::good, strength::strong>::plunder() const = delete; | |
template<> void warrior<side::good, strength::weak>::plunder() const = delete; | |
template<side Side, strength Strength> | |
void warrior<Side, Strength>::flee() const { | |
std::cout << "The weak warrior flees!\n"; | |
} | |
template<> void warrior<side::good, strength::strong>::flee() const = delete; | |
template<> void warrior<side::evil, strength::strong>::flee() const = delete; | |
template<bool Mutable> | |
class good_warrior_ref_base { | |
protected: | |
std::conditional_t<Mutable, void*, const void*> m_ptr; | |
strength m_strength; | |
public: | |
template<strength Strength> | |
good_warrior_ref_base(const warrior<side::good, Strength>& w): m_ptr{&w}, m_strength{Strength} {} | |
template<strength Strength> | |
good_warrior_ref_base(warrior<side::good, Strength>& w): m_ptr{&w}, m_strength{Strength} {} | |
template<strength Strength> | |
decltype(auto) get_as() const { | |
assert(Strength == m_strength); | |
return *static_cast< | |
std::conditional_t<Mutable, | |
warrior<side::good, Strength>, | |
const warrior<side::good, Strength> | |
>*>(m_ptr); | |
} | |
void heal() const { | |
switch(m_strength) { | |
case strength::strong: | |
return get_as<strength::strong>().heal(); | |
case strength::weak: | |
return get_as<strength::weak>().heal(); | |
} | |
__builtin_unreachable(); | |
} | |
template<typename...Args> | |
decltype(auto) insane_method(Args&&... args) const { // C++14 for returntype | |
switch(m_strength) { | |
case strength::strong: | |
return get_as<strength::strong>().insane_method(std::forward<Args...>(args...)); | |
case strength::weak: | |
return get_as<strength::weak>().insane_method(std::forward<Args...>(args...)); | |
} | |
__builtin_unreachable(); | |
} | |
}; | |
using good_warrior_ref = good_warrior_ref_base<false>; | |
class good_warrior_mut_ref: public good_warrior_ref_base<true> { | |
public: | |
using good_warrior_ref_base::good_warrior_ref_base; | |
void nonconst_method() { | |
switch(m_strength) { | |
case strength::strong: | |
return get_as<strength::strong>().nonconst_method(); | |
case strength::weak: | |
return get_as<strength::weak>().nonconst_method(); | |
} | |
__builtin_unreachable(); | |
} | |
}; | |
void heal(good_warrior_ref w) { | |
w.heal(); | |
} | |
void use_noconst(good_warrior_mut_ref w) { | |
w.nonconst_method(); | |
} | |
int main() { | |
warrior<side::good, strength::strong> warrior_1; | |
warrior_1.attack(); | |
warrior<side::good, strength::weak> warrior_2; | |
//warrior_2.attack(); // compiler-error | |
heal(warrior_1); | |
heal(warrior_2); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment