4

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);
}
doctopus
  • 5,349
  • 8
  • 53
  • 105
  • IMHO, the function is not recommended. For example, there isn't a standard method to insert into a container. Also, I don't believe the savings of this function is worth the hassle and development time. – Thomas Matthews Dec 01 '20 at 18:42
  • 1
    Take a look at the `` header of the standard library. Can you see a single algorithm that receives a container argument? No? There is a reason for that. – n. m. could be an AI Dec 01 '20 at 18:45

2 Answers2

4

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

Live Demo

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
4

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);
}
jxh
  • 69,070
  • 8
  • 110
  • 193