Parámetros de la plantilla de C++ anidados para funciones
templates c++11 (3)
Quiero tener una función de plantilla en C ++, donde un parámetro de plantilla es una plantilla de otro parámetro de plantilla. Si eso no tiene ningún sentido, tome el siguiente código que imprime un std :: vector con plantilla en el tipo T
template <typename T>
void print_vector(std::vector<T> &vec)
{
for(auto v: vec)
std::cout << v << " ";
std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_vector(vec);
Quiero generalizar aún más esta función para contenedores STL distintos del vector. Pero no sé cómo "anidar" los parámetros de la plantilla, de modo que el contenedor esté templado en el tipo T. He intentado lo siguiente sin éxito
template <typename T, template <typename TT> V>
void print_container(V<T> &con)
{
for(auto c: con)
std::cout << c << " ";
std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_container(vec);
Estoy seguro de que esto se ha respondido aquí antes, pero no puedo encontrar los términos de búsqueda para encontrar la respuesta.
EDIT : Gracias @ForEveR, su respuesta fue correcta en el dinero! Todas las respuestas a mi pregunta observaron que no es necesario tener el tipo de "almacenamiento" tipo T, y que la siguiente solución es adecuada para el ejemplo que di:
template <typename C>
void print_container(C &con)
{
for(auto v: con)
std::cout << v << " ";
std::cout << std::endl;
}
Desafortunadamente, el caso de uso real que motivó la pregunta fue un poco más complicado. La rutina toma múltiples contenedores, como este ejemplo de álgebra lineal con una matriz y clase vectorial:
template <typename MATRIX, typename VECTOR>
void mat_vec_multiply(const MATRIX &A, const VECTOR &x, VECTOR &y)
{
// implement y = A*x;
}
Suponga que ambas clases, MATRIX y VECTOR, deben tener plantillas en la misma clase de almacenamiento subyacente (es decir, double, float, int ...). La idea es que especificando explícitamente T como un parámetro de plantilla, podemos aplicar esto:
template < typename T,
template<typename> class MATRIX,
template<typename> class VECTOR>
void mat_vec_multiply(const MATRIX<T> &A, const VECTOR<T> &x, VECTOR<T> &y)
{
// implement y = A*x;
}
Desafortunadamente, estoy usando el compilador nvcc de CUDA, que no tiene ningún soporte para las construcciones de C ++ 11 (en mi ejemplo, solo utilicé C ++ 11 porque es menos detallado). Así que no puedo usar std :: is_same y static_assert, aunque supongo que podría rodar mi propia is_same (o usar BOOST) con la suficiente facilidad. ¿Cuál es la "mejor práctica" en este caso, donde deseo aplicar el parámetro de plantilla de commone para las clases de almacenamiento?
Es mejor que no hagas eso en absoluto; Considere simplemente la creación de plantillas en el recipiente
template <typename C>
void print_container(const C& container)
{
for(auto v: container)
std::cout << v << " ";
std::cout << std::endl;
}
Si necesita el tipo almacenado en la función, puede usar: `typedef typename C :: value_type T;
No estoy seguro de haber entendido lo que quieres pero puedes intentar esto:
template <typename V>
void print_vector(V &vec)
{
for(auto v: vec)
std::cout << v << " ";
std::cout << std::endl;
}
...
std::vector<double> vec(5);
...
print_vector(vec);
El punto aquí es que normalmente no necesita la construcción como template < template V< typename T> >
porque toda la plantilla de template V< typename T>
se puede generalizar al tipo V
std::vector
tiene dos parámetros, tipo y asignador. Prueba esto
template <typename T, typename Alloc, template <typename, typename> class V>
void print_container(V<T, Alloc> &con)
{
}
print_container(vec);
Esto funcionará para vector
, list
, etc., pero no funcionará con map
, set
.
Sin embargo, ya que usa auto
, puede usar C ++ 11 y luego puede hacer esto:
template <typename T, template <typename, typename...> class V, typename... Args>
void print_container(V<T, Args...> &con)
o
template <template <typename, typename...> class V, typename... Args>
void print_container(V<Args...> &con)
Y, por supuesto, la forma más sencilla es hacer algo como
template<typename C>
void print_container(C& con)
Probablemente con algunos controles para deducir, que C
es realmente contenedor.
template<typename C>
auto print_container(C& con) -> decltype(con.begin(), void())