Since you cannot verify the name of participants without a template, you will need to make the intersection in a different way.
In fact, you cannot (yet) verify from which structure. But with tuples you can. And you can make a union if each member of the tuple has different types.
Start with a simple shell for your port type:
template<char name> struct port_wrapper : port {};
Then determine which modules are created from tuples:
template<char... names> using module = std::tuple<port_wrapper<names>...>; using module1 = module<'a', 'b', 'c'>; using module2 = module<'c', 'd', 'e'>;
After that, you can use metafunctions to calculate the intersection of the module:
template<char...> struct name_list {}; template<typename> struct to_name_list_impl; template<char... names> struct to_name_list_impl<std::tuple<port_wrapper<names>...>> { using list = name_list<names...>; }; template<typename module> using to_name_list = typename to_name_list_impl<module>::list; template <char, typename> struct name_list_contains; template <char c> struct name_list_contains<c, name_list<>> : std::false_type {}; template <char c, char head, char... tail> struct name_list_contains<c, name_list<head, tail...>> : name_list_contains<c, name_list<tail...>> {}; template <char c, char... tail> struct name_list_contains<c, name_list<c, tail...>> : std::true_type {}; template<typename, typename> struct name_list_concat; template<char... names1, char... names2> struct name_list_concat<name_list<names1...>, name_list<names2...>> { using list = name_list<names1..., names2...>; }; template<typename...> struct all_names; template<> struct all_names<> { using list = name_list<>; }; template<char... names, typename... Tail> struct all_names<name_list<names...>, Tail...> { using list = typename name_list_concat<name_list<names...>, typename all_names<Tail...>::list>::list; }; template<typename> struct unique_names; template<> struct unique_names<name_list<>> { using list = name_list<>; }; template<char first, char... others> struct unique_names<name_list<first, others...>> { using uniques = typename unique_names<name_list<others...>>::list; using list = std::conditional_t< name_list_contains<first, uniques>::value, uniques, typename name_list_concat<uniques, name_list<first>>::list >; }; template<typename> struct module_union_impl; template<char... names> struct module_union_impl<name_list<names...>> { using module_name_union = module<names...>; }; template<typename... modules> using module_union = typename module_union_impl< typename unique_names< typename all_names< to_name_list<modules>... >::list >::list >::module_name_union;
With this code, you can now use module_union as follows:
using top_level_module = module_union<module1, module2>;
Live at coliru
Additionnaly, you can make a utility that builds a traditional structure from a tuple of ports.
It was fun.