Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested C++ template parameters for functions

I want to have a templated function in C++, where one template parameter is itself a template of another template parameter. If that doesn't make any sense, take the following code that prints a std::vector that is templated on type 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); 

I want to further generalize this function for STL containers other than vector. But I don't know how to "nest" the template parameters such that the container is templated on type T. I have tried the following with no success

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); 

I am sure this has been answered here before, but I can't find the search terms to find the answer.


Thanks @ForEveR. Your response was right on the money! All of the responses to my question observed that there is no need have the "storage" type T templated, with the following solution being adequate for the example I gave:

template <typename C> void print_container(C &con) {     for(auto v: con)         std::cout << v << " ";     std::cout << std::endl; } 

Unfortunately, the actual use case that motivated the question was a little bit more complicated. The routine takes multiple containers, like this linear algebra example with a matrix and vector class:

template <typename MATRIX, typename VECTOR> void mat_vec_multiply(const MATRIX &A, const VECTOR &x, VECTOR &y) {     // Implement y = A*x; } 

Assume that both the MATRIX and VECTOR classes have to be templated on the same underlying storage class (i.e., double, float, int, etc.). The idea is that by explicitly specifying T as a template parameter, we can enforce this:

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

Unfortunately, I am using the CUDA compiler nvcc, which doesn't have any support for C++11 constructs (I just used C++11 in my example because it is less verbose). So I can't use std::is_same and static_assert, though I suppose I could roll my own is_same (or use Boost) easily enough. What is the "best practice" in this case, where I want to enforce the common template parameter for the storage classes?

like image 738
bcumming Avatar asked Dec 04 '13 10:12

bcumming


People also ask

Can a template parameter be a function?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

Can we pass Nontype parameters to templates?

Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.

Which is correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

Which template can have multiple parameters?

C++ Class Template with multiple parameters You can also use multiple parameters in your class template.


1 Answers

std::vector has two parameters, type and allocator. Try this

template <typename T, typename Alloc, template <typename, typename> class V> void print_container(V<T, Alloc> &con) { }  print_container(vec); 

This will work for vector, list, etc., but will not work with map, set.

However, since you use auto you can use C++11 and then you can to this:

template <typename T, template <typename, typename...> class V, typename... Args> void print_container(V<T, Args...> &con) 

or

template <template <typename, typename...> class V, typename... Args> void print_container(V<Args...> &con) 

and of course most simple way is to do something like

template<typename C> void print_container(C& con) 

probably with some checks for deduce, that C is really container.

template<typename C> auto print_container(C& con) -> decltype(con.begin(), void()) 
like image 137
ForEveR Avatar answered Oct 05 '22 04:10

ForEveR