I would personally think about using overloading, instead of so many classes. And you will also need, somehow, a tag selector.
Let us start with the tag selector.
// Note: to start simply we assume that a tag is only ever present once
// if not, we just need to add an index.
template <typename Tag,
typename Type,
typename std::disable_if<same_type<Tag, typename get<Head>::tag>::type>
struct has_tag: std::false_type {};
template <typename Tag,
typename Type,
typename std::enable_if<same_type<Tag, typename get<Head>::tag>::type>
struct has_tag: std::true_type {};
template <typename Tag, typename Head, typename... Tail>
struct tag_selector {
using type = if_<has_tag<Tag, Head>,
Head,
typename tag_selector<Tag, Tail...>::type>;
}; // tag_selector
template <typename Tag>
struct tag_selector {}; // compile-time error if tag absent
// A helper function
template <typename Result, typename Head, typename... Tail>
auto tag_select_impl(std::true_type, Head const& head, Tail const&... tail)
-> Result const&
{
return Head;
}
template <typename Result, typename Head, typename NH, typename... Tail>
auto tag_select_impl(std::false_type, Head const&, NH const& nh, Tail const&... tail)
-> Result const&
{
return tag_select_impl<Result>(has_tag<Tag, NH>{}, nh, tail);
}
// And now the runtime function
template <typename Tag, typename Head, typename... Tail>
auto tag_select(Tag, Head const& head, Tail const&... tail) ->
typename tag_selector<Tag, Head, Tail...>::type const&
{
using Result = typename tag_selector<Tag, Head, Tail...>::type;
return tag_select_impl<Result>(has_tag<Tag, Head>{}, head, tail);
}
So, in brief, all of this is just so that tag_select(tag, args...)
returns the first argument that matches the tag
. The good news is that it is pretty generic :)
Then, we can actually implement the algorithm:
void internal_impl(First const& first, Second const& second) {
std::cout << first.value() << " " << second.someFunction() << "\n";
} // internal_impl
template <typename A, typename B>
void interface(A const& a, B const& b) {
internal_impl(tag_select(A_tag{}, a, b), tag_select(B_tag{}, a, b));
}
Note: the tag select is 1. murky (probably can do cleaner) and 2. only allows const&
arguments for now which is annoying; there is probably a way to solve both issues.