После попытки сделать std::get<N>
(std::tuple)
сам метод, я не очень уверен, как это реализовано компиляторами. я знаю std::tuple
имеет такой конструктор,
tuple(Args&&... args);
Но что именно args...
назначен? Я думаю, что это полезно для того, чтобы знать, как std::get
работает, потому что аргументы должны быть размещены где-то для доступа к ним …
Вот грубая игрушечная реализация tuple
класс
Во-первых, несколько шаблонов метапрограммирования, чтобы представить последовательность целых чисел:
template<int...> struct seq {};
template<int max, int... s> struct make_seq:make_seq< max-1, max-1, s... > {};
template<int... s> struct make_seq<0, s...> {
typedef seq<s...> type;
};
template<int max> using MakeSeq = typename make_seq<max>::type;
Далее, помеченный класс, который на самом деле хранит данные:
template<int x, typename Arg>
struct foo_storage {
Arg data;
};
Этот метод тегирования является общим шаблоном, когда мы хотим связать данные с каким-либо тегом во время компиляции (в данном случае, целое число). Тег ( int
здесь) обычно не используется нигде в хранилище, просто используется для обозначения хранилища.
foo_helper
распаковывает последовательность и набор аргументов в кучу foo_storage
и наследует от них линейным способом. Это довольно распространенный шаблон — если вы делаете это много, вы в конечном итоге создаете инструменты метапрограммирования, которые делают это для вас:
template<typename Seq, typename... Args>
struct foo_helper {};
template<int s0, int... s, typename A0, typename... Args>
struct foo_helper<seq<s0, s...>, A0, Args...>:
foo_storage<s0, A0>,
foo_helper<seq<s...>, Args...>
{};
Моя сырая tuple
тип, foo
, создает пакет из последовательности индексов и аргументов и передает его помощнику выше. Затем помощник создает группу помеченных данных, содержащих родительские классы:
template<typename... Args>
struct foo: foo_helper< MakeSeq<sizeof...(Args)>, Args... > {};
Я удалил все из тела foo
потому что это не нужно для реализации get
,
get
довольно просто: мы берем тип хранения (не тип кортежа), а явный template
аргумент N
однозначно, какой из foo_storage<n, T>
мы собираемся получить доступ. Теперь, когда у нас есть тип хранилища, мы просто возвращаем поле данных:
template<int N, typename T>
T& get( foo_storage<N, T>& f )
{ return f.data; }
template<int N, typename T>
T const& get( foo_storage<N, T> const& f )
{ return f.data; }
Мы используем механизмы перегрузки языка C ++ для выполнения тяжелой работы. Когда вы вызываете функцию с экземпляром класса, этот экземпляр, как и каждый из родительских классов, пропускается, чтобы посмотреть, можно ли сопоставить любой из них. С N
исправлено, есть только один родительский класс, который является допустимым аргументом, поэтому родительский класс (и, следовательно, T
) выводится автоматически.
И, наконец, базовый тестовый код:
#include <iostream>
int main() {
foo<int, double> f;
get<0>( f ) = 7;
get<1>( f ) = 3.14;
std::cout << get<0>(f) << "," << get<1>(f) << "\n";
}
Других решений пока нет …