Как работает std :: get?

После попытки сделать std::get<N>(std::tuple) сам метод, я не очень уверен, как это реализовано компиляторами. я знаю std::tuple имеет такой конструктор,

tuple(Args&&... args);

Но что именно args... назначен? Я думаю, что это полезно для того, чтобы знать, как std::get работает, потому что аргументы должны быть размещены где-то для доступа к ним …

5

Решение

Вот грубая игрушечная реализация 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";
}
8

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]