Reputation: 5657
I have this function that I'd like to use for a container of strings, like vector<string>
or set<string>
. Obviously templating seems like the best solution here but I'm not sure how to template the container. I tried this but it doesn't work:
template<class T>
string pack_addrs(T<string>& caddrs) {
string res = "";
for (string addr : caddrs) {
res += addr + ",";
}
return res.substr(0, res.size()-1);
}
Upvotes: 5
Views: 856
Reputation: 70502
You can allow your template to use any class generically, but assert that it must behave like a container. In particular, you can assert that it has a value_type
that matches std::string
.
template<class C>
std::string pack_addrs(C& caddrs) {
static_assert(std::is_same<typename C::value_type, std::string>::value);
std::string res = "";
for (std::string addr : caddrs) {
res += addr + ",";
}
return res.substr(0, res.size()-1);
}
Or, you can use SFINAE to disable the function if the type of the argument does not match the desired trait.
template<class C,
typename std::enable_if<
std::is_same<typename C::value_type,
std::string>::value>::type* = nullptr>
std::string pack_addrs(C& caddrs) {
std::string res = "";
for (std::string addr : caddrs) {
res += addr + ",";
}
return res.substr(0, res.size()-1);
}
Upvotes: 4
Reputation: 598448
When a template parameter is itself a templated type, you can use a template template parameter for it, eg:
template <template<class...> class Container>
string pack_addrs(const Container<string>& caddrs) {
string res;
for (const string &addr : caddrs) {
res += addr + ",";
}
return res.substr(0, res.size()-1);
}
This code will allow you to pass in any templated container that accepts std::string
as its 1st template parameter (even if it takes additional template parameters, like an allocator, etc), and that satisfies the requirements of a range-for loop.
Upvotes: 4