#include <list>
#include <typeinfo>
#include <type_traits>
#include <set>
#include <utility>

#include <iostream>

//Warning, C++11 code ahead
typedef std::set<std::string> _cendent_list;

// You can also extend this to include a list of non-family members
//     if you want to catch those.
template <class Origin, class Relative>
void find_relationship_helper3(_cendent_list&, _cendent_list& des, std::true_type)
{
    des.insert(typeid(Relative).name());
}

template <class Origin, class Relative>
void find_relationship_helper3(_cendent_list&, _cendent_list&, std::false_type)
{}

template <class Origin, class Relative>
void find_relationship_helper2(_cendent_list& ante, _cendent_list&, std::true_type)
{
    ante.insert(typeid(Relative).name());
}

template <class Origin, class Relative>
void find_relationship_helper2(_cendent_list& ante, _cendent_list& des, std::false_type)
{
    find_relationship_helper3<Origin, Relative>
        (ante, des, typename std::is_base_of<Origin, Relative>::type());
}

template <class Origin, class Relative>
void find_relationship_helper(_cendent_list& ante, _cendent_list& des)
{
    find_relationship_helper2<Origin, Relative>
        (ante, des, typename std::is_base_of<Relative, Origin>::type());
}

template <class Origin, class Relative, class Relative2, class... FamilyPack>
void find_relationship_helper(_cendent_list& ante, _cendent_list& des)
{
    find_relationship_helper<Origin, Relative>(ante, des);
    find_relationship_helper<Origin, Relative2, FamilyPack...>(ante, des);
}


//Important function here
template <class Origin, class... FamilyPack>
std::pair<_cendent_list, _cendent_list> find_relationship()
{
    _cendent_list ante, des;
    find_relationship_helper<Origin, FamilyPack...>(ante, des);
    return std::make_pair(ante, des);
}

struct Parent{};
struct Child : Parent{};
struct Grandchild : Child{};

int main(){
	auto Parent_list = find_relationship<Parent, Child, Grandchild>();
	auto Child_list = find_relationship<Child, Parent, Grandchild>();
	auto Grandchild_list = find_relationship<Grandchild, Parent, Child>();
	
	std::cout << "Parent:\n"
		<< "\tAntecendents:\n";
	for(const auto& t : Parent_list.first)
	    std::cout << "\t\t- " << t<< '\n';
    std::cout << "\tDescendents:\n";
	for(const auto& t : Parent_list.second)
	    std::cout << "\t\t- " << t<< '\n';
    std::cout << std::endl;
	    
	std::cout << "Child:\n"
		<< "\tAntecendents:\n";
	for(const auto& t : Child_list.first)
	    std::cout << "\t\t- " << t<< '\n';
    std::cout << "\tDescendents:\n";
	for(const auto& t : Child_list.second)
	    std::cout << "\t\t- " << t<< '\n';
    std::cout << std::endl;
	    
	std::cout << "Grandchild:\n"
		<< "\tAntecendents:\n";
	for(const auto& t : Grandchild_list.first)
	    std::cout << "\t\t- " << t<< '\n';
    std::cout << "\tDescendents:\n";
	for(const auto& t : Grandchild_list.second)
	    std::cout << "\t\t- " << t << '\n';
	
	return 0;
}
