Skip to content

Instantly share code, notes, and snippets.

@Fiona-J-W
Created May 17, 2014 16:55
Show Gist options
  • Save Fiona-J-W/e91a8aeda78c5e040299 to your computer and use it in GitHub Desktop.
Save Fiona-J-W/e91a8aeda78c5e040299 to your computer and use it in GitHub Desktop.
#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