Created
July 20, 2021 01:09
-
-
Save dno89/5c05ff8a7982c514c951f1581ddfb47e to your computer and use it in GitHub Desktop.
Static Polymorphism With Some Metaprogramming Fun
This file contains 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 <type_traits> | |
#include <variant> | |
#include <string> | |
#include <iostream> | |
#include <vector> | |
namespace detail { | |
// create a variant with Ts... and add NewT iff Add == true. | |
template<bool Add, typename NewT, typename... Ts> | |
struct add_if_unique_helper { | |
using type = std::variant<NewT, Ts...>; | |
}; | |
template<typename NewT, typename... Ts> | |
struct add_if_unique_helper<false, NewT, Ts...> { | |
using type = std::variant<Ts...>; | |
}; | |
// add NewT to TypeContainerT if it doesn't have NewT alredy | |
template<typename NewT, typename TypeContainerT> | |
struct add_if_unique{}; | |
// specialization required to have access to all the types contained in TypeContainerT | |
template<typename NewT, typename... Ts> | |
struct add_if_unique<NewT, std::variant<Ts...>> { | |
using type = typename add_if_unique_helper< | |
(!std::is_same_v<NewT, Ts> && ...), | |
NewT, | |
Ts... | |
>::type; | |
}; | |
// aggregate all the types into a variant, discarding the repeated types. | |
template<typename... Ts> | |
struct aggregate_unique { | |
using type = std::variant<>; | |
}; | |
template<typename NewT, typename... Ts> | |
struct aggregate_unique<NewT, Ts...> { | |
// add recursively one type at a time. | |
using type = typename add_if_unique<NewT, typename aggregate_unique<Ts...>::type> | |
::type; | |
}; | |
template<typename... Ts> | |
using deduce_variant_t = typename aggregate_unique<Ts...>::type; | |
} | |
// Create a vector of variant whose type can contain all Ts... but without repetitions. | |
template<typename... Ts> | |
auto CreateVariantVector(Ts&& ... args) -> std::vector<detail::deduce_variant_t<Ts...>> { | |
using variant_t = detail::deduce_variant_t<Ts...>; | |
return std::vector{ | |
variant_t(std::forward<Ts>(args))... | |
}; | |
} | |
class H { | |
public: | |
void draw() const { | |
std::cout << "H"; | |
} | |
}; | |
class E { | |
public: | |
void draw() const { | |
std::cout << "E"; | |
} | |
}; | |
class O { | |
public: | |
void draw() const { | |
std::cout << "O"; | |
} | |
}; | |
class NewLine { | |
public: | |
void draw() const { | |
std::cout << "\n"; | |
} | |
}; | |
template<char C> | |
class RepeatedChar { | |
int count_; | |
public: | |
explicit RepeatedChar(int count) : count_(count) | |
{} | |
void draw() const { | |
std::cout << std::string(count_, C); | |
} | |
}; | |
template<typename IteratorT> | |
void Draw(IteratorT begin, IteratorT end) { | |
for(; begin != end; ++begin) { | |
std::visit([](const auto& drawable){drawable.draw();}, *begin); | |
} | |
} | |
int main() { | |
auto line1 = CreateVariantVector(H{}, E{}, RepeatedChar<'L'>{2}, RepeatedChar<' '>{2}, O{}, NewLine{}); | |
auto line2 = CreateVariantVector(RepeatedChar<'C'>{1}, RepeatedChar<'+'>{2}, NewLine{}); | |
// print type of line1 | |
// typename decltype(line1)::x; | |
Draw(line1.begin(), line1.end()); | |
Draw(line2.begin(), line2.end()); | |
std::cout.flush(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment