Sorry to chime in so late in the discussion. What about a syntax similar to this? int main() { auto s = join("Hello ", ", World.", " The hex for ", 58, " is ", std::hex, 58); std::cout << s << std::endl; s = join(separator(" : "), "a", "b", std::hex, 200 , std::quoted("banana")); std::cout << s << std::endl; } Which would produce the following output: Hello , World. The hex for 58 is 3a a : b : c8 : “banana" sample implementation (io manipulators may be incomplete, some efficiency gains could be made by re-implementing ostringstream more cleverly): #include <sstream> #include <iostream> #include <iomanip> namespace detail { template<class SepStr> struct separator_object { template<class T> std::ostream& operator ()(std::ostream& s, T&& t) const { return s << sep << t; } // // other iomanp specialisations here // std::ostream& operator ()(std::ostream& s, std::ios_base&(*t)(std::ios_base&)) const { t(s); return s; } SepStr const& sep; }; struct no_separator_object { template<class T> std::ostream& operator ()(std::ostream& s, T&& t) const { return s << t; } }; template<class Separator, class String, class...Rest> auto join(Separator&& sep, String&& s, Rest&&...rest) { std::ostringstream ss; ss << s; using expand = int []; void(expand{0, ((sep(ss, rest)), 0)... }); return ss.str(); }; } template<class Sep> static constexpr auto separator(Sep const& sep) { using sep_type = std::remove_const_t<std::remove_reference_t<Sep>>; return detail::separator_object<sep_type> { sep }; } template<class SepObject, class String, class...Rest> auto join(const detail::separator_object<SepObject>& sep, String&& s, Rest&&...rest) { return detail::join(sep, std::forward<String>(s), std::forward<Rest>(rest)...); }; template<class String, class...Rest> auto join(String&& s, Rest&&...rest) { return detail::join(detail::no_separator_object(), std::forward<String>(s), std::forward<Rest>(rest)...); }; int main() { auto s = join("Hello ", ", World.", " The hex for ", 58, " is ", std::hex, 58); std::cout << s << std::endl; s = join(separator(" : "), "a", "b", std::hex, 200 , std::quoted("banana")); std::cout << s << std::endl; }