Вопрос

I'm giving C++0x a try and I was wondering how to solve the following problem that came up. I've got a variadic template class:

template<typename... T>
class MyLovelyClass {

 template<typename SomeType>
 void DoSthWithStorageOfSomeType();

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

The function there is suppose to do some sort of manipulation on the vector in m_storage tuple that corresponds to the SomeType template argument (or compile time fail if it doesn't). How one can do this?

My idea was to find the index of SomeType in parameter pack and then use std::get to obtain the appropriate vector, but I don't know how to to do the first part.

Это было полезно?

Решение

Here's some code to do a linear search of a tuple for the first type U it finds, and gives a compile-time error if it can't find U. Note if the tuple contains multiple U's it only finds the first one. Not sure if that is the policy you want or not. It returns the compile-time index into the tuple of the first U. Perhaps you could use it as the index into your std::get.

Disclaimer: Thrown together for this answer. Only lightly tested. Edge cases such as an empty tuple have a nasty error message that could be improved. etc.

#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';
}

Другие советы

C++14 solution:

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

Use:

cout << index<A, Args...>() << "\n";

I added support for the "type not found" case to Elazar's solution, by returning 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;
}

EDIT: I switched to using the size of the parameter pack as the "not found" index value. This is like the STL usage of a "one past the end" index or iterator and makes a more elegant solution:

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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top