Я еще никогда не использовал функцию вариадических шаблонов C ++ 0x, но следующий код компилируется в G ++ 4.5:
template <typename... Args>
struct tuple;
template <typename T, typename... Args>
struct tuple<T, Args...> {
T value;
tuple<Args...> inner;
};
template <typename T>
struct tuple<T> {
T value;
};
Однако их инициализация ... странная, потому что нам нужно nest внутренние значения:
int main() {
tuple<int> n1 = { 23 };
tuple<int, float> n2 = { 42, { 0.5f } };
tuple<std::string, double, int> n3 = { "hello, world", { 3.14, { 97 } } };
}
Получение значений, конечно, немного утомительно.Простейший метод, вероятно, состоит в том, чтобы предоставить шаблон функции get<N>()
.
Но мы не можем напрямую реализовать get
, поскольку шаблоны функций не могут быть частично специализированными.Либо нам нужно использовать SFINAE (читай: boost::enable_if
), либо нам нужно делегировать фактическую функцию get
типу, который может быть частично специализированным.
Далее я сделал последнее.Но сначала нам понадобится еще одна черта вспомогательного типа: nth_type
, которая возвращает соответствующий тип возврата функции get
:
template <unsigned N, typename... Args>
struct nth_type;
template <unsigned N, typename T, typename... Args>
struct nth_type<N, T, Args...> : nth_type<N - 1, Args...> { };
template <typename T, typename... Args>
struct nth_type<0, T, Args...> {
typedef T type;
};
Easy-peasy.Просто возвращает n -ый тип в списке типов.
Теперь мы можем написать нашу get
функцию:
template <unsigned N, typename... Args>
inline typename nth_type<N, Args...>::type get(tuple<Args...>& tup) {
return get_t<N, Args...>::value(tup);
}
Как я уже сказал, это только делегатызадание.Нет, важная персона.На практике мы, вероятно, хотим иметь еще одну перегрузку для const
кортежей (но тогда на практике мы будем использовать существующий тип tuple
).
Теперь для убийства, за которым следует легкий салат:
template <unsigned N, typename... Args>
struct get_t;
template <unsigned N, typename T, typename... Args>
struct get_t<N, T, Args...> {
static typename nth_type<N, T, Args...>::type value(tuple<T, Args...>& tup) {
return get_t<N - 1, Args...>::value(tup.inner);
}
};
template <typename T, typename... Args>
struct get_t<0, T, Args...> {
static T value(tuple<T, Args...>& tup) {
return tup.value;
}
};
И все.Мы можем проверить это, напечатав некоторые значения в наших ранее определенных переменных:
std::cout << get<0>(n1) << std::endl; // 23
std::cout << get<0>(n2) << std::endl; // 42
std::cout << get<0>(n3) << std::endl; // hello, world
std::cout << get<1>(n2) << std::endl; // 0.5
std::cout << get<1>(n3) << std::endl; // 3.14
std::cout << get<2>(n3) << std::endl; // 97
Человек, это забавно возиться с вариадическими шаблонами.