Dear Christof, you did a much more thorough (and correct) job on researching the use of "join" in other languages, while mine was really quick. I respect that and feel embarrassed that I didn't do a better job myself.
To make things clear, a naive implementation of join, that only supports strings could look like this:
template<typename Iterator> auto join(const std::string& separator, Iterator i, Iterator end) -> std::string { auro rval = std::ostringstream{};
auto addSeparator = false; for(; i != end; ++i) { if( addSeparator ) rval << separator; else addSeparator = true;
rval << *i; }
return rval.str(); }
A naive implementation of concat(), could look like this:
auto concat_impl() -> std::ostringstream { return {}; }
template
auto concat_impl(Args&& ... args, LastArg&& last_arg) -> std::ostringstream { return concat_impl(std::forward(args)...) << last_arg; } template
auto concat(Args&& ... args) -> std::string { return concat_impl(std::forward(args)...).str(); } Both implementations are untested. They are just here to emphasize my point.
I still think that "join" is a better name for what you call "concat", as the function is literally joining various pieces and that name does not require an abbreviation. What you call "join" could be called "join_sequence". Best regards, Hans