Положение типа в пакете параметров шаблона - PullRequest
9 голосов
/ 17 мая 2011

Я пробую C ++ 0x и мне было интересно, как решить следующую возникшую проблему.У меня есть класс шаблона variadic:

template<typename... T>
class MyLovelyClass {

 template<typename SomeType>
 void DoSthWithStorageOfSomeType();

 private:
  std::tuple<std::vector<T>...> m_storage;
};

Предполагается, что функция выполняет какие-то манипуляции с вектором в кортеже m_storage, который соответствует аргументу шаблона SomeType (или если во время компиляции происходит сбой, если«т).Как можно это сделать?

Моя идея состояла в том, чтобы найти индекс SomeType в пакете параметров и затем использовать std :: get для получения соответствующего вектора, но я не знаю, как сделать первую часть.

Ответы [ 3 ]

7 голосов
/ 17 мая 2011

Вот некоторый код для выполнения линейного поиска кортежа для первого типа U, который он находит, и выдает ошибку времени компиляции, если он не может найти U. Обратите внимание, если кортеж содержит несколько U, он находит только первый,Не уверен, что это политика, которую вы хотите или нет.Он возвращает индекс времени компиляции в кортеж первого U. Возможно, вы могли бы использовать его в качестве индекса в вашем std::get.

Отказ от ответственности: Собран вместе для этого ответа.Только слегка проверено.В пограничных случаях, таких как пустой кортеж, есть неприятное сообщение об ошибке, которое можно улучшить.и т. д.

#include <type_traits>
#include <tuple>

template <class Tuple, class T, std::size_t Index = 0>
struct find_first;

template <std::size_t Index, bool Valid>
struct find_first_final_test
    : public std::integral_constant<std::size_t, Index>
{
};

template <std::size_t Index>
struct find_first_final_test<Index, false>
{
    static_assert(Index == -1, "Type not found in find_first");
};

template <class Head, class T, std::size_t Index>
struct find_first<std::tuple<Head>, T, Index>
    : public find_first_final_test<Index, std::is_same<Head, T>::value>
{
};

template <class Head, class ...Rest, class T, std::size_t Index>
struct find_first<std::tuple<Head, Rest...>, T, Index>
    : public std::conditional<std::is_same<Head, T>::value,
                    std::integral_constant<std::size_t, Index>,
                    find_first<std::tuple<Rest...>, T, Index+1>>::type
{
};

#include <iostream>

int main()
{
    typedef std::tuple<char, int, short> T;
    std::cout << find_first<T, double>::value << '\n';
}
2 голосов
/ 26 декабря 2014

C ++ 14 решение:

template <typename T, typename U=void, typename... Types>
constexpr size_t index() {
    return std::is_same<T, U>::value ? 0 : 1 + index<T, Types...>();
}

Использование:

cout << index<A, Args...>() << "\n";
0 голосов
/ 08 января 2015

Я добавил поддержку для случая «тип не найден» в решение Elazar, вернув SIZE_MAX:

template <class T, class F = void, class ...R>
constexpr size_t TypeIndex() {
    return is_same<T,F>::value
         ? 0
         : is_same<F,void>::value || TypeIndex<T,R...>() == SIZE_MAX
         ? SIZE_MAX
         : TypeIndex<T,R...>() + 1;
}

РЕДАКТИРОВАТЬ: я переключился на использование размера пакета параметров в качестве индекса «не найден»значение.Это похоже на использование STL индекса или итератора «один за другим» и дает более элегантное решение:

template <class T, class F = void, class ...R>
constexpr size_t TypeIndex() {
    return is_same<T,F>::value || is_same<F,void>::value ? 0 : TypeIndex<T,R...>() + 1;
}
...