Вложенные параметры шаблона С++ для функций

Я хочу иметь шаблонную функцию в С++, где один параметр шаблона сам является шаблоном другого параметра шаблона. Если это не имеет никакого смысла, возьмите следующий код, который печатает 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.