I'd like to write a simple string split function.
The function should take one std::basic_string and a delimiter (possibly a CharT or std::basic_string), and put the result into a ContainerT.
My first try is
template <typename StringT, typename DelimiterT, typename ContainerT>
void split(
const StringT &str, const DelimiterT &delimiters, ContainerT &conts) {
conts.clear();
std::size_t start = 0, end;
std::size_t len = delimiters.size();
while ((end = str.find(delimiters, start)) != StringT::npos) {
if (end - start) {
conts.emplace_back(str, start, end - start);
}
start = end + len;
}
if (start != StringT::npos && start < str.size()) {
conts.emplace_back(str, start, str.size() - start);
}
}
My final goal is to extend this function to achieve:
- The final results are always
std::basic_string<CharT>put into someconts. - The first argument
strcould bestd::basic_string<CharT>,const CharT*or a string literal. - The second argument
delimitercould be achar, or astd::basic_string<CharT>/const CharT*/string literal, meaning that the length of the delimiter is greater than 1, e.g. splitaaa,,bbb,cwith,,givesaaa/bbb,c. - The third argument can be any sequence container from
STL.
Since one usually deals with modern stings in C++, 2 may be std::basic_string<CharT> only for simplification.
Given that the function (template) can be overloaded, I wonder
- At least how many functions would I need in this situation?
- And what's the best practice to design such functions(How to write more generic functions)? For example, maybe to make the above function work with a
const CharT*delimiter, the linestd::size_t len = delimiters.size();must be changed to somestd::distance(...)?
Update:
A revalent code review is added here.