My goal is to create a URL query params from std::map<std::string, std::string>. For example, we call to_query_params( {{"one","1"},{"two","2"}} ) and we get ?one=1&two=2.
Is this a good way of doing it?
std::string to_query_params(std::map<std::string, std::string> map)
{
if (map.empty()){
return "";
}
auto map_beg = std::begin(map);
auto concat = [](const decltype(map)::value_type& a){
return a.first+"="+a.second;
};
std::string result("?"+concat(*map_beg));
std::for_each(std::next(std::begin(map)),
std::end(map),
[&](decltype(map)::value_type param){
result+="&"+concat(param);
});
return result;
}
EDIT AFTER COMMENTS
Ok, after given answers and comments I ended up with something like this:
template< typename Container >
std::string to_query_params(Container&& container) // 1.
{
if (container.empty()){
return "";
}
std::string result;
for( const auto& item : container ) {
result.append("&")
.append(std::get<0>(item))
.append("=")
.append(std::get<1>(item)); // 2.
}
assert(result.size() > 0);
result[0]='?';
return result;
}
- we're independent of underlying container, be it
multimap,map,vector<tuple<string,string>>, etc; - and we're independent of
r/lvaluenessof param being able to callto_query_params(generate_params()); - as of the container - I'll opt for
std::vector<std::tuple<std::string, std::string>>, as we do not need to access elements, but iterate over them, so linear memory block will be cache-friendly;
-
- thank's to
appendwe're not creating useless copies;
- thank's to
std::stringstreamis hudge and heavy, and I tend to avoid it as much as I can;