#include <iostream>
#include <tuple>
#include <type_traits>
#include <functional>

template<template<typename...> typename To, typename Tuple>
struct tuple_template_forward;
template<template<typename...> typename To, typename... Args>
struct tuple_template_forward<To, std::tuple<Args...>> final
{
	using type = To<Args...>;
};

template<typename... Tuples>
struct tuple_type_cat final
{
	using type = typename std::function<decltype(std::tuple_cat<Tuples...>)>::result_type;
};

namespace impl
{
	template<typename Type, typename... Args>
	struct tuple_contains;
	template<typename Type, typename First, typename... Rest>
	struct tuple_contains<Type, First, Rest...> final
	{
		static constexpr bool value = (std::is_same<Type, First>::value || tuple_contains<Type, Rest...>::value);
	};
	template<typename Type>
	struct tuple_contains<Type> final
	: std::false_type
	{
	};
}

template<typename Tuple, typename Type>
struct tuple_contains final
{
	static constexpr bool value = tuple_template_forward<impl::tuple_contains, typename tuple_type_cat<std::tuple<Type>, Tuple>::type>::type::value;
};

namespace impl
{
	template<typename Current, typename... Args>
	struct tuple_prune;
	template<typename Current, typename First, typename... Rest>
	struct tuple_prune<Current, First, Rest...> final
	{
		using type = typename std::conditional
		<
			::tuple_contains<Current, First>::value,
			tuple_prune<Current, Rest...>,
			tuple_prune<typename tuple_type_cat<Current, std::tuple<First>>::type, Rest...>
		>::type::type;
	};
	template<typename Current>
	struct tuple_prune<Current> final
	{
		using type = Current;
	};
}

template<typename Tuple>
struct tuple_prune final
{
	using type = typename tuple_template_forward<impl::tuple_prune, typename tuple_type_cat<std::tuple<std::tuple<>>, Tuple>::type>::type::type;
};

struct Test
{
	virtual ~Test() = 0;
};
inline Test::~Test() = default;

int main()
{
	static_assert(std::is_same<std::tuple<void, Test>, typename tuple_prune<std::tuple<void, void, Test, void, Test, Test>>::type>::value, "error");
}
