2011-05-17 7 views
9

Estoy probando C++ 0x y me preguntaba cómo resolver el siguiente problema que surgió. Tengo una clase de plantilla variadic:Posición de un tipo en un paquete de parámetros de plantilla variadic

template<typename... T> 
class MyLovelyClass { 

template<typename SomeType> 
void DoSthWithStorageOfSomeType(); 

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

La función no se supone que debe hacer algún tipo de manipulación en el vector en la tupla m_storage que se corresponde con el argumento de plantilla SomeType (o tiempo de compilación fallará si doesn' t). ¿Cómo se puede hacer esto?

Mi idea era encontrar el índice de SomeType en el paquete de parámetros y luego usar std :: get para obtener el vector apropiado, pero no sé cómo hacer la primera parte.

+0

C++ 14, y por lo tanto algunas implementaciones de la biblioteca estándar proporcionan 'std :: conseguir > (m_storage) '. Debería verificar y ver si el suyo tiene esta característica, hace las cosas muy fáciles. –

Respuesta

7

Aquí hay un código para hacer una búsqueda lineal de una tupla para el primer tipo U que encuentra, y da un error en tiempo de compilación si no puede encontrar U. Nota si la tupla contiene múltiples U solo encuentra la primera uno. No estoy seguro si esa es la política que quiere o no. Devuelve el índice de tiempo de compilación en la tupla de la primera U. Quizás podría usarlo como el índice en su std::get.

Descargo de responsabilidad: Arrojados juntos para esta respuesta. Solo ligeramente probado. Las mayúsculas y minúsculas, como una tupla vacía, tienen un desagradable mensaje de error que podría mejorarse. 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'; 
} 
+0

Gracias - ¡Me gusta! ¿Puedo sugerir dos cosas: 1) Agregar una herencia de std :: integral_constant al caso falso para evitar el error adicional de que :: value no se encuentra. 2) Agregar una especialización para la plantilla de tupla vacía struct find_first , T, Index> : public find_first_final_test }; –

+1

Espero que use este código como base para construir exactamente lo que necesita, como agregar sus dos sugerencias. ¡Corre con eso! :-) –

+0

Bien. Gracias :) –

1

C++ 14 solución:

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

Uso:

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

Yay segfaults en g ++ 5.4 cuando el tipo no está en la lista (no he intentado 6). –

0

añadí apoyo para el caso "no tipo que se encuentra" a la solución de Elazar, devolviendo 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: Cambié a usar el tamaño del paquete de parámetros como el valor del índice "no encontrado". Esto es como el uso de STL de un "uno más allá del final" índice o iterador y hace que una solución más elegante:

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; 
} 
Cuestiones relacionadas