В современном С++ мы можем писать например так:
std::for_each(threads.begin(), threads.end(), std::mem_fun_ref(&std::thread::join));
Это очень круто, мы пишем в близком к функциональному подходу стиле и читается это как настоящий язык: для каждого потока от начала до конца вызови функцию по ссылке - соединиться.
Обычно так и я пишу свой код на работе.
А можем написать вот так, мерко, противно, императивно:
for(auto& t: threads)
t.join();
Так я пишу свой код на работе после того как удалил тот, что написал сначала.