Perhaps you should follow the pattern of the for_each algorithm. Follow the link for an example of how that algorithm can be defined.
http://www.cplusplus.com/reference/algorithm/for_each/
If you want a printer that is generic then you should prefer using iterators as inputs to the algorithm. Then it makes no difference which container supplies them, and your function could even take pointers to C arrays. Take that further, and if you want it to work for user defined types, then user defined types should have overloaded stream operators to support them.
Take a look at this as well, and consider even more options.
http://www.cplusplus.com/reference/iterator/ostream_iterator/
I couldn't post this in a comment, but here is a simplified version of the other answer with a main for testing. It was tested at http://www.compileonline.com/compile_cpp11_online.php
Of course you might need specializations for other types such as double or user defined types.
#include <vector>
#include <list>
#include <iostream>
template <typename T>
void print_container(const T&);
template <typename T>
void print(const T& e) { std::cout << e; }
template <typename T>
void print_container(const T& c) {
std::cout << "[";
bool isFirst = true;
for (const auto& e : c) {
if (isFirst) isFirst = false;
else std::cout << ",";
print(e);
}
std::cout << "]";
}
int main()
{
std::vector<int> v = {0, 1, 3, 5, 7, 9};
std::list<int> l = {0, 1, 3, 5, 7, 9};
print_container(v);
print_container(l);
}