Ответ 1
В С++ 17 агрегатная инициализация сможет инициализировать общедоступные базовые классы. Таким образом, вы можете использовать наследование + расширение пакета для создания такого класса. Чтобы заставить его работать со структурированными привязками, вам нужно будет открыть интерфейс кортежа: specialize std::tuple_size
и std::tuple_element
и предоставить get
функцию для вашего класса:
//Headers used by "many" class implementation
#include <utility>
#include <tuple>
namespace rw {
namespace detail {
template <size_t index, typename T>
struct many_holder
{ T value; };
template <typename idx_seq, typename... Types>
struct many_impl;
template <size_t... Indices, typename... Types>
struct many_impl<std::index_sequence<Indices...>, Types...>: many_holder<Indices, Types>...
{};
}
template <typename... Types>
struct many: detail::many_impl<typename std::make_index_sequence<sizeof...(Types)>, Types...>
{};
template<size_t N, typename... Types>
auto get(const rw::many<Types...>& data) -> const std::tuple_element_t<N, rw::many<Types...>>&
{
const rw::detail::many_holder<N, std::tuple_element_t<N, rw::many<Types...>>>& holder = data;
return holder.value;
}
}
namespace std {
template <typename... Types>
struct tuple_size<rw::many<Types...>> : std::integral_constant<std::size_t, sizeof...(Types)>
{};
template< std::size_t N, class... Types >
struct tuple_element<N, rw::many<Types...> >
{ using type = typename tuple_element<N, std::tuple<Types...>>::type; };
}
//Headers used for testing
#include <iostream>
#include <string>
int main()
{
rw::many<int, std::string, int> x = {42, "Hello", 11};
std::cout << std::tuple_size<decltype(x)>() << '\n' << rw::get<1>(x);
}
Демо (сейчас работает только в clang 3.9): http://melpon.org/wandbox/permlink/9NBqkcbOuURFvypt
Примечания:
- В демонстрации есть прокомментированная реализация
nth_type
, которую вы можете использовать для реализацииtuple_element
напрямую и не откладывать ее на реализациюtuple_element<tuple>
. -
get<many>
должна быть либо функцией-членомmany
, либо помещаться в соответствующее пространство имен для структурированных привязок для работы. Вы не должны перегружатьstd::get
(в любом случае это будет UB). - Я оставил реализацию
get
для ссылок не const и ссылок на r-значение в качестве упражнения для читателя. - Нет примера использования структурированных привязок и руководств, потому что clang их не поддерживает (на самом деле я не знаю компилятора, который их поддерживает). Теоретически
template<typename... Types> many(Types...) -> many<Types...>;
должен работать.