Вложенные параметры шаблона С++ для функций
Я хочу иметь шаблонную функцию в С++, где один параметр шаблона сам является шаблоном другого параметра шаблона. Если это не имеет никакого смысла, возьмите следующий код, который печатает std::vector, шаблон которого задан по типу 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);
Я хочу еще больше обобщить эту функцию для контейнеров STL, отличных от вектора. Но я не знаю, как "вложить" параметры шаблона таким образом, чтобы контейнер был настроен на тип T. Я пробовал следующее без успеха
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);
Я уверен, что на этот вопрос ответили ранее, но я не могу найти условия поиска, чтобы найти ответ.
EDIT: Спасибо @ForEveR, ваш ответ был прав на деньги! Во всех ответах на мой вопрос было отмечено, что нет необходимости в шаблоне типа "хранения", при этом для примера, который я дал, было достаточным следующее решение:
template <typename C>
void print_container(C &con)
{
for(auto v: con)
std::cout << v << " ";
std::cout << std::endl;
}
К сожалению, фактический прецедент, который мотивировал вопрос, был немного сложнее. Процедура принимает несколько контейнеров, например, этот пример линейной алгебры с матричным и векторным классом:
template <typename MATRIX, typename VECTOR>
void mat_vec_multiply(const MATRIX &A, const VECTOR &x, VECTOR &y)
{
// implement y = A*x;
}
Предположим, что оба класса MATRIX и VECTOR должны быть шаблонизированы в одном и том же базовом классе хранения (т.е. double, float, int...). Идея состоит в том, что, явно указывая T как параметр шаблона, мы можем обеспечить это:
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;
}
К сожалению, я использую компилятор CUDA nvcc, который не имеет поддержки для конструкций С++ 11 (я просто использовал С++ 11 в моем примере, потому что он менее подробный). Поэтому я не могу использовать std:: is_same и static_assert, хотя, я полагаю, я мог бы свернуть собственный is_same (или использовать BOOST) достаточно легко. Что такое "лучшая практика" в этом случае, когда я хочу применить параметр шаблона commone для классов хранения?
Ответы
Ответ 1
std::vector
имеет два параметра, тип и распределитель.
Попробуйте это
template <typename T, typename Alloc, template <typename, typename> class V>
void print_container(V<T, Alloc> &con)
{
}
print_container(vec);
Это будет работать для vector
, list
и т.д., но не будет работать с map
, set
.
Однако, поскольку вы используете auto
, вы можете использовать С++ 11, а затем можете:
template <typename T, template <typename, typename...> class V, typename... Args>
void print_container(V<T, Args...> &con)
или
template <template <typename, typename...> class V, typename... Args>
void print_container(V<Args...> &con)
и, конечно, самый простой способ - сделать что-то вроде
template<typename C>
void print_container(C& con)
возможно, с некоторыми проверками на вывод, что C
действительно контейнер.
template<typename C>
auto print_container(C& con) -> decltype(con.begin(), void())
Ответ 2
Вам лучше не делать этого вообще; рассмотрите только шаблоны на контейнере
template <typename C>
void print_container(const C& container)
{
for(auto v: container)
std::cout << v << " ";
std::cout << std::endl;
}
Если вам нужен сохраненный тип функции, вы можете использовать: `typedef typename C:: value_type T;
Ответ 3
Я не уверен, что я понял, чего вы хотите, но вы можете попробовать это:
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);
Дело в том, что обычно вам не нужна конструкция типа template < template V< typename T> >
, потому что весь шаблон template V< typename T>
можно обобщить, чтобы набрать V
.