Skip to content

Instantly share code, notes, and snippets.

@dno89
Created July 20, 2021 01:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dno89/5c05ff8a7982c514c951f1581ddfb47e to your computer and use it in GitHub Desktop.
Save dno89/5c05ff8a7982c514c951f1581ddfb47e to your computer and use it in GitHub Desktop.
Static Polymorphism With Some Metaprogramming Fun
#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