Reputation: 14632
How to write a template function that accepts nested templates?
For example, I'd like to write following function:
void print(const T1<T2<T3>> &container);
Had tried:
template<
template<typename> class T1,
template<typename> class T2,
class T3
>
void print(const T1<T2<T3>> &container) {
for (auto &e : container)
for (auto x : e)
std::cout<<e<<' ';
std::cout<<'\n';
}
int main()
{
std::vector<std::deque<int>> c = {{1,2},{3}};
print(c);
return 0;
}
Compile error from g++:
a.cc: In function ‘int main()’:
a.cc:23:14: error: no matching function for call to ‘print(std::vector<std::deque<int> >&)’
print(c);
^
a.cc:12:10: note: candidate: template<template<class> class T1, template<class> class T2, class T3> void print(const T1<T2<T3> >&)
void print(const T1<T2<T3>> &container) {
^
a.cc:12:10: note: template argument deduction/substitution failed:
a.cc:23:14: error: wrong number of template arguments (2, should be 1)
print(c);
^
a.cc:8:32: note: provided for ‘template<class> class T1’
template<typename> class T1,
^
Compile error from Clang:
a.cc:23:7: error: no matching function for call to 'print'
print(c);
^~~~~
a.cc:12:10: note: candidate template ignored: substitution failure : template template argument has different template parameters than its corresponding
template template parameter
void print(const T1<T2<T3>> &container) {
^
Also tried:
template<
template<template<typename> class> class T1,
template<typename> class T2,
class T3
>
void print(const T1<T2<T3>> &container);
but it still has compile error even before deduction:
a.cc:12:25: error: template argument for template template parameter must be a class template or type alias template
void print(const T1<T2<T3>> &container) {
^
---- EDIT ----
What if I'd like to return a pointer to one of it's type?
T3 get(const T1<T2<T3>> &container);
Upvotes: 3
Views: 5145
Reputation: 21576
Though, I'll prefer you use a single template and pick the typedefs from it.
Something like:
template<typename T1>
void print(const T1& container) { //As opposed to const T1<T2<T3>> &container
using T2 = typename T1::value_type;
using T3 = typename T2::value_type;
for (auto &e : container)
for (auto x : e)
std::cout<<x<<' ';
std::cout<<'\n';
}
But if you must go your way, then this will work (std::vector
and std::deque
are actually declared with two template parameters, though the allocator is defaulted):
template<
template<typename, typename> class T1,
template<typename, typename> class T2,
typename AllocT1, typename AllocT2,
typename T3
>
void print(const T1<T2<T3, AllocT2>, AllocT1> &container) {
for (auto &e : container)
for (auto x : e)
std::cout<<x<<' ';
std::cout<<'\n';
}
But there is a neater solution:
template<typename T1,
typename T2 = typename T1::value_type,
typename T3 = typename T2::value_type>
T3 print(const T1& container){
for (auto &e : container)
for (auto x : e)
std::cout<<x<<' ';
std::cout<<'\n';
return T3();
}
The choice is expressly yours. :-)
EDIT:
What if I'd like to return a pointer to one of it's type?
T3 get(const T1<T2<T3>> &container);
In C++14, you can simply use an auto
placeholder return type, or use the latter solution above.
Upvotes: 7
Reputation: 42899
A single template parameter will work for you:
template<class T>
void print(const T& container) {
for (auto &e : container)
for (auto x : e) std::cout << x << ' ';
std::cout << '\n';
}
Upvotes: 3