Convert a vector to a string





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







80















I have a vector<int> container that has integers (e.g. {1,2,3,4}) and I would like to convert to a string of the form



"1,2,3,4"


What is the cleanest way to do that in C++?
In Python this is how I would do it:



>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'









share|improve this question




















  • 1





    Closely related: stackoverflow.com/questions/4850473/…

    – Ciro Santilli 新疆改造中心996ICU六四事件
    Mar 8 '15 at 21:39


















80















I have a vector<int> container that has integers (e.g. {1,2,3,4}) and I would like to convert to a string of the form



"1,2,3,4"


What is the cleanest way to do that in C++?
In Python this is how I would do it:



>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'









share|improve this question




















  • 1





    Closely related: stackoverflow.com/questions/4850473/…

    – Ciro Santilli 新疆改造中心996ICU六四事件
    Mar 8 '15 at 21:39














80












80








80


14






I have a vector<int> container that has integers (e.g. {1,2,3,4}) and I would like to convert to a string of the form



"1,2,3,4"


What is the cleanest way to do that in C++?
In Python this is how I would do it:



>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'









share|improve this question
















I have a vector<int> container that has integers (e.g. {1,2,3,4}) and I would like to convert to a string of the form



"1,2,3,4"


What is the cleanest way to do that in C++?
In Python this is how I would do it:



>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'






c++ vector tostring






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 17 '18 at 19:54









jww

54.6k42240523




54.6k42240523










asked Sep 16 '09 at 3:14









dzhelildzhelil

8,9772391139




8,9772391139








  • 1





    Closely related: stackoverflow.com/questions/4850473/…

    – Ciro Santilli 新疆改造中心996ICU六四事件
    Mar 8 '15 at 21:39














  • 1





    Closely related: stackoverflow.com/questions/4850473/…

    – Ciro Santilli 新疆改造中心996ICU六四事件
    Mar 8 '15 at 21:39








1




1





Closely related: stackoverflow.com/questions/4850473/…

– Ciro Santilli 新疆改造中心996ICU六四事件
Mar 8 '15 at 21:39





Closely related: stackoverflow.com/questions/4850473/…

– Ciro Santilli 新疆改造中心996ICU六四事件
Mar 8 '15 at 21:39












19 Answers
19






active

oldest

votes


















86














Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.



You could use a stringstream ...



std::stringstream ss;
for(size_t i = 0; i < v.size(); ++i)
{
if(i != 0)
ss << ",";
ss << v[i];
}
std::string s = ss.str();


You could also make use of std::for_each instead.






share|improve this answer


























  • I think you mean array.size() not v.size(), no?

    – Mark Elliot
    Sep 16 '09 at 3:35






  • 1





    ya whatever the vector is called.

    – Brian R. Bondy
    Sep 16 '09 at 3:37






  • 2





    That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

    – sbi
    Sep 16 '09 at 8:56






  • 1





    why not just use string.append?

    – Baiyan Huang
    Jun 27 '14 at 9:56






  • 11





    answer is incomplete without #include <sstream>

    – renadeen
    Mar 20 '16 at 20:02



















42














Using std::copy and std::ostream_iterator we can get something as elegant as python.



#include <iostream>
#include <sstream>
#include <algorithm>
#include <iterator>


int main()
{
int array = {1,2,3,4};

std::copy(array, array+4, std::ostream_iterator<int>(std::cout,","));
}


See this question for a little class I wrote. This will not print the trailing comma. Also if we assume that C++14 will continue to give us range based equivalents of algorithms like this:



namespace std {
// I am assuming something like this in the C++14 standard
// I have no idea if this is correct but it should be trivial to write if it does not appear.
template<typename C, typename I>
void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
}
using POI = PrefexOutputIterator;
int main()
{
int array = {1,2,3,4};
std::copy(array, POI(std::cout, ","));
// ",".join(map(str,array)) // closer
}





share|improve this answer





















  • 11





    I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

    – 1800 INFORMATION
    Sep 16 '09 at 4:13






  • 2





    Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

    – Martin York
    Sep 16 '09 at 4:36






  • 19





    Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

    – Steve Jessop
    Sep 16 '09 at 10:19











  • Why doesn't it work?

    – jalf
    Sep 16 '09 at 12:31






  • 1





    You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

    – Dan
    Sep 16 '09 at 15:59



















16














Another alternative is the use of std::copy and the ostream_iterator class:



#include <iterator>  // ostream_iterator
#include <sstream> // ostringstream
#include <algorithm> // copy

std::ostringstream stream;
std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
std::string s=stream.str();
s.erase(s.length()-1);


Also not as nice as Python.
For this purpose, I created a join function:



template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
T result;
for (A it=begin;
it!=end;
it++)
{
if (!result.empty())
result.append(t);
result.append(*it);
}
return result;
}


Then used it like this:



std::string s=join(array.begin(), array.end(), std::string(","));


You might ask why I passed in the iterators. Well, actually I wanted to reverse the array, so I used it like this:



std::string s=join(array.rbegin(), array.rend(), std::string(","));


Ideally, I would like to template out to the point where it can infer the char type, and use string-streams, but I couldn't figure that out yet.






share|improve this answer


























  • Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

    – sbi
    Sep 16 '09 at 9:51











  • Your join function can be used with vectors as well? May you please give example, I'm new to C++.

    – Noitidart
    Jan 15 '17 at 1:09











  • Can you change the iterator to a preincrement in the answer?

    – Millie Smith
    Sep 8 '17 at 3:12





















16














You can use std::accumulate. Consider the following example



if (v.empty() 
return std::string();
std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
(const std::string& a, int b){
return a + ',' + std::to_string(b);
});





share|improve this answer































    12














    With Boost and C++11 this could be achieved like this:



    auto array = {1,2,3,4};
    join(array | transformed(tostr), ",");


    Well, almost. Here's the full example:



    #include <array>
    #include <iostream>

    #include <boost/algorithm/string/join.hpp>
    #include <boost/range/adaptor/transformed.hpp>

    int main() {
    using boost::algorithm::join;
    using boost::adaptors::transformed;
    auto tostr = static_cast<std::string(*)(int)>(std::to_string);

    auto array = {1,2,3,4};
    std::cout << join(array | transformed(tostr), ",") << std::endl;

    return 0;
    }


    Credit to Praetorian.



    You can handle any value type like this:



    template<class Container>
    std::string join(Container const & container, std::string delimiter) {
    using boost::algorithm::join;
    using boost::adaptors::transformed;
    using value_type = typename Container::value_type;

    auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
    return join(container | transformed(tostr), delimiter);
    };





    share|improve this answer

































      10














      This is just an attempt to solve the riddle given by 1800 INFORMATION's remark on his second solution lacking genericity, not an attempt to answer the question:



      template <class Str, class It>
      Str join(It begin, const It end, const Str &sep)
      {
      typedef typename Str::value_type char_type;
      typedef typename Str::traits_type traits_type;
      typedef typename Str::allocator_type allocator_type;
      typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
      ostringstream_type;
      ostringstream_type result;

      if(begin!=end)
      result << *begin++;
      while(begin!=end) {
      result << sep;
      result << *begin++;
      }
      return result.str();
      }


      Works On My Machine(TM).






      share|improve this answer


























      • Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

        – Grault
        Apr 9 '15 at 4:01











      • @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

        – sbi
        Apr 9 '15 at 4:46











      • I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

        – Grault
        Apr 11 '15 at 2:52













      • @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

        – sbi
        Apr 11 '15 at 7:41











      • Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

        – zett42
        Sep 26 '18 at 19:58





















      7














      Lots of template/ideas. Mine's not as generic or efficient, but I just had the same problem and wanted to throw this into the mix as something short and sweet. It wins on shortest number of lines... :)



      std::stringstream joinedValues;
      for (auto value: array)
      {
      joinedValues << value << ",";
      }
      //Strip off the trailing comma
      std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);





      share|improve this answer



















      • 1





        Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

        – Millie Smith
        Sep 8 '17 at 4:31











      • Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

        – ifyalciner
        Dec 7 '17 at 23:31



















      4














      If you want to do std::cout << join(myVector, ",") << std::endl;, you can do something like:



      template <typename C, typename T> class MyJoiner
      {
      C &c;
      T &s;
      MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
      public:
      template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
      template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
      };

      template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
      {
      auto i = mj.c.begin();
      if (i != mj.c.end())
      {
      o << *i++;
      while (i != mj.c.end())
      {
      o << mj.s << *i++;
      }
      }

      return o;
      }

      template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
      {
      return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
      }


      Note, this solution does the join directly into the output stream rather than creating a secondary buffer and will work with any types that have an operator<< onto an ostream.



      This also works where boost::algorithm::join() fails, when you have a vector<char*> instead of a vector<string>.






      share|improve this answer































        2














        I like 1800's answer. However I would move the first iteration out of the loop as as the result of the if statement only changes once after the first iteration



        template <class T, class A>
        T join(const A &begin, const A &end, const T &t)
        {
        T result;
        A it = begin;
        if (it != end)
        {
        result.append(*it);
        ++it;
        }

        for( ;
        it!=end;
        ++it)
        {
        result.append(t);
        result.append(*it);
        }
        return result;
        }


        This can of course be reduced down to fewer statements if you like:



        template <class T, class A>
        T join(const A &begin, const A &end, const T &t)
        {
        T result;
        A it = begin;
        if (it != end)
        result.append(*it++);

        for( ; it!=end; ++it)
        result.append(t).append(*it);
        return result;
        }





        share|improve this answer


























        • You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

          – sbi
          Sep 16 '09 at 19:29











        • Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

          – iain
          Sep 17 '09 at 13:12











        • Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

          – iain
          Sep 17 '09 at 13:20






        • 1





          @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

          – sbi
          Sep 17 '09 at 14:50






        • 1





          @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

          – iain
          Sep 18 '09 at 9:50



















        2














        There are some interesting attempts at providing an elegant solution to the problem. I had an idea to use templated streams to effectively answer the OP's original dilemma. Though this is an old post, I'm hoping future users who stumble upon this will find my solution beneficial.



        First, some answers (including the accepted answer) do not promote re-usability. Since C++ doesn't provide an elegant way to join strings in the standard library (that I have seen), it becomes important to create one that is flexible and reusable. Here's my shot at it:



        // Replace with your namespace //
        namespace my {
        // Templated join which can be used on any combination of streams, iterators and base types //
        template <typename TStream, typename TIter, typename TSeperator>
        TStream& join(TStream& stream, TIter begin, TIter end, TSeperator seperator) {
        // A flag which, when true, has next iteration prepend our seperator to the stream //
        bool sep = false;
        // Begin iterating through our list //
        for (TIter i = begin; i != end; ++i) {
        // If we need to prepend a seperator, do it //
        if (sep) stream << seperator;
        // Stream the next value held by our iterator //
        stream << *i;
        // Flag that next loops needs a seperator //
        sep = true;
        }
        // As a convenience, we return a reference to the passed stream //
        return stream;
        }
        }


        Now to use this, you could simply do something like the following:



        // Load some data //
        std::vector<int> params;
        params.push_back(1);
        params.push_back(2);
        params.push_back(3);
        params.push_back(4);

        // Store and print our results to standard out //
        std::stringstream param_stream;
        std::cout << my::join(param_stream, params.begin(), params.end(), ",").str() << std::endl;

        // A quick and dirty way to print directly to standard out //
        my::join(std::cout, params.begin(), params.end(), ",") << std::endl;


        Note how the use of streams makes this solution incredibly flexible as we can store our result in a stringstream to reclaim it later, or we can write directly to the standard out, a file, or even to a network connection implemented as a stream. The type being printed must simply be iteratable and compatible with the source stream. STL provides various streams which are compatible with a large range of types. So you could really go to town with this. Off the top of my head, your vector can be of int, float, double, string, unsigned int, SomeObject*, and more.






        share|improve this answer































          2














          string s;
          for (auto i : v)
          s += (s.empty() ? "" : ",") + to_string(i);





          share|improve this answer



















          • 5





            Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

            – paper1111
            Jan 23 at 10:18











          • The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

            – aberaud
            Feb 17 at 20:10





















          1














          I've created an helper header file to add an extended join support.



          Just add the code below to your general header file and include it when needed.



          Usage Examples:



          /* An example for a mapping function. */
          ostream&
          map_numbers(ostream& os, const void* payload, generic_primitive data)
          {
          static string names = {"Zero", "One", "Two", "Three", "Four"};
          os << names[data.as_int];
          const string* post = reinterpret_cast<const string*>(payload);
          if (post) {
          os << " " << *post;
          }
          return os;
          }

          int main() {
          int arr = {0,1,2,3,4};
          vector<int> vec(arr, arr + 5);
          cout << vec << endl; /* Outputs: '0 1 2 3 4' */
          cout << join(vec.begin(), vec.end()) << endl; /* Outputs: '0 1 2 3 4' */
          cout << join(vec.begin(), vec.begin() + 2) << endl; /* Outputs: '0 1 2' */
          cout << join(vec.begin(), vec.end(), ", ") << endl; /* Outputs: '0, 1, 2, 3, 4' */
          cout << join(vec.begin(), vec.end(), ", ", map_numbers) << endl; /* Outputs: 'Zero, One, Two, Three, Four' */
          string post = "Mississippi";
          cout << join(vec.begin() + 1, vec.end(), ", ", map_numbers, &post) << endl; /* Outputs: 'One Mississippi, Two mississippi, Three mississippi, Four mississippi' */
          return 0;
          }


          The code behind the scene:



          #include <iostream>
          #include <vector>
          #include <list>
          #include <set>
          #include <unordered_set>
          using namespace std;

          #define GENERIC_PRIMITIVE_CLASS_BUILDER(T) generic_primitive(const T& v) { value.as_##T = v; }
          #define GENERIC_PRIMITIVE_TYPE_BUILDER(T) T as_##T;

          typedef void* ptr;

          /** A union that could contain a primitive or void*,
          * used for generic function pointers.
          * TODO: add more primitive types as needed.
          */
          struct generic_primitive {
          GENERIC_PRIMITIVE_CLASS_BUILDER(int);
          GENERIC_PRIMITIVE_CLASS_BUILDER(ptr);
          union {
          GENERIC_PRIMITIVE_TYPE_BUILDER(int);
          GENERIC_PRIMITIVE_TYPE_BUILDER(ptr);
          };
          };

          typedef ostream& (*mapping_funct_t)(ostream&, const void*, generic_primitive);
          template<typename T>
          class Join {
          public:
          Join(const T& begin, const T& end,
          const string& separator = " ",
          mapping_funct_t mapping = 0,
          const void* payload = 0):
          m_begin(begin),
          m_end(end),
          m_separator(separator),
          m_mapping(mapping),
          m_payload(payload) {}

          ostream&
          apply(ostream& os) const
          {
          T begin = m_begin;
          T end = m_end;
          if (begin != end)
          if (m_mapping) {
          m_mapping(os, m_payload, *begin++);
          } else {
          os << *begin++;
          }
          while (begin != end) {
          os << m_separator;
          if (m_mapping) {
          m_mapping(os, m_payload, *begin++);
          } else {
          os << *begin++;
          }
          }
          return os;
          }
          private:
          const T& m_begin;
          const T& m_end;
          const string m_separator;
          const mapping_funct_t m_mapping;
          const void* m_payload;
          };

          template <typename T>
          Join<T>
          join(const T& begin, const T& end,
          const string& separator = " ",
          ostream& (*mapping)(ostream&, const void*, generic_primitive) = 0,
          const void* payload = 0)
          {
          return Join<T>(begin, end, separator, mapping, payload);
          }

          template<typename T>
          ostream&
          operator<<(ostream& os, const vector<T>& vec) {
          return join(vec.begin(), vec.end()).apply(os);
          }

          template<typename T>
          ostream&
          operator<<(ostream& os, const list<T>& lst) {
          return join(lst.begin(), lst.end()).apply(os);
          }

          template<typename T>
          ostream&
          operator<<(ostream& os, const set<T>& s) {
          return join(s.begin(), s.end()).apply(os);
          }

          template<typename T>
          ostream&
          operator<<(ostream& os, const Join<T>& vec) {
          return vec.apply(os);
          }





          share|improve this answer

































            1














            Here's a generic C++11 solution that will let you do



            int main() {
            vector<int> v {1,2,3};
            cout << join(v, ", ") << endl;
            string s = join(v, '+').str();
            }


            The code is:



            template<typename Iterable, typename Sep>
            class Joiner {
            const Iterable& i_;
            const Sep& s_;
            public:
            Joiner(const Iterable& i, const Sep& s) : i_(i), s_(s) {}
            std::string str() const {std::stringstream ss; ss << *this; return ss.str();}
            template<typename I, typename S> friend std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j);
            };

            template<typename I, typename S>
            std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j) {
            auto elem = j.i_.begin();
            if (elem != j.i_.end()) {
            os << *elem;
            ++elem;
            while (elem != j.i_.end()) {
            os << j.s_ << *elem;
            ++elem;
            }
            }
            return os;
            }

            template<typename I, typename S>
            inline Joiner<I,S> join(const I& i, const S& s) {return Joiner<I,S>(i, s);}





            share|improve this answer

































              1














              The following is a simple and practical way to convert elements in a vector to a string:



              std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
              std::ostringstream result;
              for (const auto number : numbers) {
              if (result.tellp() > 0) { // not first round
              result << delimiter;
              }
              result << number;
              }
              return result.str();
              }


              You need to #include <sstream> for ostringstream.






              share|improve this answer

































                0














                as @capone did ,



                std::string join(const std::vector<std::string> &str_list , 
                const std::string &delim=" ")
                {
                if(str_list.size() == 0) return "" ;
                return std::accumulate( str_list.cbegin() + 1,
                str_list.cend(),
                str_list.at(0) ,
                [&delim](const std::string &a , const std::string &b)
                {
                return a + delim + b ;
                } ) ;
                }

                template <typename ST , typename TT>
                std::vector<TT> map(TT (*op)(ST) , const vector<ST> &ori_vec)
                {
                vector<TT> rst ;
                std::transform(ori_vec.cbegin() ,
                ori_vec.cend() , back_inserter(rst) ,
                [&op](const ST& val){ return op(val) ;} ) ;
                return rst ;
                }


                Then we can call like following :



                int main(int argc , char *argv)
                {
                vector<int> int_vec = {1,2,3,4} ;
                vector<string> str_vec = map<int,string>(to_string, int_vec) ;
                cout << join(str_vec) << endl ;
                return 0 ;
                }


                just like python :



                >>> " ".join( map(str, [1,2,3,4]) )





                share|improve this answer































                  0














                  I use something like this



                  namespace std
                  {

                  // for strings join
                  string to_string( string value )
                  {
                  return value;
                  }

                  } // namespace std

                  namespace // anonymous
                  {

                  template< typename T >
                  std::string join( const std::vector<T>& values, char delimiter )
                  {
                  std::string result;
                  for( typename std::vector<T>::size_type idx = 0; idx < values.size(); ++idx )
                  {
                  if( idx != 0 )
                  result += delimiter;
                  result += std::to_string( values[idx] );
                  }
                  return result;
                  }

                  } // namespace anonymous





                  share|improve this answer































                    0














                    I started out with @sbi's answer but most of the time ended up piping the resulting string to a stream so created the below solution that can be piped to a stream without the overhead of creating the full string in memory.



                    It is used as follows:



                    #include "string_join.h"
                    #include <iostream>
                    #include <vector>

                    int main()
                    {
                    std::vector<int> v = { 1, 2, 3, 4 };
                    // String version
                    std::string str = join(v, std::string(", "));
                    std::cout << str << std::endl;
                    // Directly piped to stream version
                    std::cout << join(v, std::string(", ")) << std::endl;
                    }


                    Where string_join.h is:



                    #pragma once

                    #include <iterator>
                    #include <sstream>

                    template<typename Str, typename It>
                    class joined_strings
                    {
                    private:
                    const It begin, end;
                    Str sep;

                    public:
                    typedef typename Str::value_type char_type;
                    typedef typename Str::traits_type traits_type;
                    typedef typename Str::allocator_type allocator_type;

                    private:
                    typedef std::basic_ostringstream<char_type, traits_type, allocator_type>
                    ostringstream_type;

                    public:
                    joined_strings(It begin, const It end, const Str &sep)
                    : begin(begin), end(end), sep(sep)
                    {
                    }

                    operator Str() const
                    {
                    ostringstream_type result;
                    result << *this;
                    return result.str();
                    }

                    template<typename ostream_type>
                    friend ostream_type& operator<<(
                    ostream_type &ostr, const joined_strings<Str, It> &joined)
                    {
                    It it = joined.begin;
                    if(it!=joined.end)
                    ostr << *it;
                    for(++it; it!=joined.end; ++it)
                    ostr << joined.sep << *it;
                    return ostr;
                    }
                    };

                    template<typename Str, typename It>
                    inline joined_strings<Str, It> join(It begin, const It end, const Str &sep)
                    {
                    return joined_strings<Str, It>(begin, end, sep);
                    }

                    template<typename Str, typename Container>
                    inline joined_strings<Str, typename Container::const_iterator> join(
                    Container container, const Str &sep)
                    {
                    return join(container.cbegin(), container.cend(), sep);
                    }





                    share|improve this answer































                      0














                      I have wrote the following code. It is based in C# string.join. It works with std::string and std::wstring and many type of vectors. (examples in comments)



                      Call it like this:



                       std::vector<int> vVectorOfIds = {1, 2, 3, 4, 5};

                      std::wstring wstrStringForSQLIn = Join(vVectorOfIds, L',');


                      Code:



                      // Generic Join template (mimics string.Join() from C#)
                      // Written by RandomGuy (stackoverflow) 09-01-2017
                      // Based on Brian R. Bondy anwser here:
                      // http://stackoverflow.com/questions/1430757/c-vector-to-string
                      // Works with char, wchar_t, std::string and std::wstring delimiters
                      // Also works with a different types of vectors like ints, floats, longs
                      template<typename T, typename D>
                      auto Join(const std::vector<T> &vToMerge, const D &delimiter)
                      {
                      // We use std::conditional to get the correct type for the stringstream (char or wchar_t)
                      // stringstream = basic_stringstream<char>, wstringstream = basic_stringstream<wchar_t>
                      using strType =
                      std::conditional<
                      std::is_same<D, std::string>::value,
                      char,
                      std::conditional<
                      std::is_same<D, char>::value,
                      char,
                      wchar_t
                      >::type
                      >::type;

                      std::basic_stringstream<strType> ss;

                      for (size_t i = 0; i < vToMerge.size(); ++i)
                      {
                      if (i != 0)
                      ss << delimiter;
                      ss << vToMerge[i];
                      }
                      return ss.str();
                      }





                      share|improve this answer

































                        0














                        Expanding on the attempt of @sbi at a generic solution that is not restricted to std::vector<int> or a specific return string type. The code presented below can be used like this:



                        std::vector<int> vec{ 1, 2, 3 };

                        // Call modern range-based overload.
                        auto str = join( vec, "," );
                        auto wideStr = join( vec, L"," );

                        // Call old-school iterator-based overload.
                        auto str = join( vec.begin(), vec.end(), "," );
                        auto wideStr = join( vec.begin(), vec.end(), L"," );


                        In the original code, template argument deduction does not work to produce the right return string type if the separator is a string literal (as in the samples above). In this case, the typedefs like Str::value_type in the function body are incorrect. The code assumes that Str is always a type like std::basic_string, so it obviously fails for string literals.



                        To fix this, the following code tries to deduce only the character type from the separator argument and uses that to produce a default return string type. This is achieved using boost::range_value, which extracts the element type from the given range type.



                        #include <string>
                        #include <sstream>
                        #include <boost/range.hpp>

                        template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
                        Str join( InputIt first, const InputIt last, const Sep& sep )
                        {
                        using char_type = typename Str::value_type;
                        using traits_type = typename Str::traits_type;
                        using allocator_type = typename Str::allocator_type;
                        using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

                        ostringstream_type result;

                        if( first != last )
                        {
                        result << *first++;
                        }
                        while( first != last )
                        {
                        result << sep << *first++;
                        }
                        return result.str();
                        }


                        Now we can easily provide a range-based overload that simply forwards to the iterator-based overload:



                        template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
                        Str join( const InputRange &input, const Sep &sep )
                        {
                        // Include the standard begin() and end() in the overload set for ADL. This makes the
                        // function work for standard types (including arrays), aswell as any custom types
                        // that have begin() and end() member functions or overloads of the standalone functions.
                        using std::begin; using std::end;

                        // Call iterator-based overload.
                        return join( begin(input), end(input), sep );
                        }


                        Live Demo at Coliru






                        share|improve this answer
























                          Your Answer






                          StackExchange.ifUsing("editor", function () {
                          StackExchange.using("externalEditor", function () {
                          StackExchange.using("snippets", function () {
                          StackExchange.snippets.init();
                          });
                          });
                          }, "code-snippets");

                          StackExchange.ready(function() {
                          var channelOptions = {
                          tags: "".split(" "),
                          id: "1"
                          };
                          initTagRenderer("".split(" "), "".split(" "), channelOptions);

                          StackExchange.using("externalEditor", function() {
                          // Have to fire editor after snippets, if snippets enabled
                          if (StackExchange.settings.snippets.snippetsEnabled) {
                          StackExchange.using("snippets", function() {
                          createEditor();
                          });
                          }
                          else {
                          createEditor();
                          }
                          });

                          function createEditor() {
                          StackExchange.prepareEditor({
                          heartbeatType: 'answer',
                          autoActivateHeartbeat: false,
                          convertImagesToLinks: true,
                          noModals: true,
                          showLowRepImageUploadWarning: true,
                          reputationToPostImages: 10,
                          bindNavPrevention: true,
                          postfix: "",
                          imageUploader: {
                          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                          allowUrls: true
                          },
                          onDemand: true,
                          discardSelector: ".discard-answer"
                          ,immediatelyShowMarkdownHelp:true
                          });


                          }
                          });














                          draft saved

                          draft discarded


















                          StackExchange.ready(
                          function () {
                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1430757%2fconvert-a-vectorint-to-a-string%23new-answer', 'question_page');
                          }
                          );

                          Post as a guest















                          Required, but never shown

























                          19 Answers
                          19






                          active

                          oldest

                          votes








                          19 Answers
                          19






                          active

                          oldest

                          votes









                          active

                          oldest

                          votes






                          active

                          oldest

                          votes









                          86














                          Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.



                          You could use a stringstream ...



                          std::stringstream ss;
                          for(size_t i = 0; i < v.size(); ++i)
                          {
                          if(i != 0)
                          ss << ",";
                          ss << v[i];
                          }
                          std::string s = ss.str();


                          You could also make use of std::for_each instead.






                          share|improve this answer


























                          • I think you mean array.size() not v.size(), no?

                            – Mark Elliot
                            Sep 16 '09 at 3:35






                          • 1





                            ya whatever the vector is called.

                            – Brian R. Bondy
                            Sep 16 '09 at 3:37






                          • 2





                            That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

                            – sbi
                            Sep 16 '09 at 8:56






                          • 1





                            why not just use string.append?

                            – Baiyan Huang
                            Jun 27 '14 at 9:56






                          • 11





                            answer is incomplete without #include <sstream>

                            – renadeen
                            Mar 20 '16 at 20:02
















                          86














                          Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.



                          You could use a stringstream ...



                          std::stringstream ss;
                          for(size_t i = 0; i < v.size(); ++i)
                          {
                          if(i != 0)
                          ss << ",";
                          ss << v[i];
                          }
                          std::string s = ss.str();


                          You could also make use of std::for_each instead.






                          share|improve this answer


























                          • I think you mean array.size() not v.size(), no?

                            – Mark Elliot
                            Sep 16 '09 at 3:35






                          • 1





                            ya whatever the vector is called.

                            – Brian R. Bondy
                            Sep 16 '09 at 3:37






                          • 2





                            That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

                            – sbi
                            Sep 16 '09 at 8:56






                          • 1





                            why not just use string.append?

                            – Baiyan Huang
                            Jun 27 '14 at 9:56






                          • 11





                            answer is incomplete without #include <sstream>

                            – renadeen
                            Mar 20 '16 at 20:02














                          86












                          86








                          86







                          Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.



                          You could use a stringstream ...



                          std::stringstream ss;
                          for(size_t i = 0; i < v.size(); ++i)
                          {
                          if(i != 0)
                          ss << ",";
                          ss << v[i];
                          }
                          std::string s = ss.str();


                          You could also make use of std::for_each instead.






                          share|improve this answer















                          Definitely not as elegant as Python, but nothing quite is as elegant as Python in C++.



                          You could use a stringstream ...



                          std::stringstream ss;
                          for(size_t i = 0; i < v.size(); ++i)
                          {
                          if(i != 0)
                          ss << ",";
                          ss << v[i];
                          }
                          std::string s = ss.str();


                          You could also make use of std::for_each instead.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Oct 6 '15 at 15:02









                          cdmh

                          2,53411839




                          2,53411839










                          answered Sep 16 '09 at 3:19









                          Brian R. BondyBrian R. Bondy

                          257k99545595




                          257k99545595













                          • I think you mean array.size() not v.size(), no?

                            – Mark Elliot
                            Sep 16 '09 at 3:35






                          • 1





                            ya whatever the vector is called.

                            – Brian R. Bondy
                            Sep 16 '09 at 3:37






                          • 2





                            That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

                            – sbi
                            Sep 16 '09 at 8:56






                          • 1





                            why not just use string.append?

                            – Baiyan Huang
                            Jun 27 '14 at 9:56






                          • 11





                            answer is incomplete without #include <sstream>

                            – renadeen
                            Mar 20 '16 at 20:02



















                          • I think you mean array.size() not v.size(), no?

                            – Mark Elliot
                            Sep 16 '09 at 3:35






                          • 1





                            ya whatever the vector is called.

                            – Brian R. Bondy
                            Sep 16 '09 at 3:37






                          • 2





                            That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

                            – sbi
                            Sep 16 '09 at 8:56






                          • 1





                            why not just use string.append?

                            – Baiyan Huang
                            Jun 27 '14 at 9:56






                          • 11





                            answer is incomplete without #include <sstream>

                            – renadeen
                            Mar 20 '16 at 20:02

















                          I think you mean array.size() not v.size(), no?

                          – Mark Elliot
                          Sep 16 '09 at 3:35





                          I think you mean array.size() not v.size(), no?

                          – Mark Elliot
                          Sep 16 '09 at 3:35




                          1




                          1





                          ya whatever the vector is called.

                          – Brian R. Bondy
                          Sep 16 '09 at 3:37





                          ya whatever the vector is called.

                          – Brian R. Bondy
                          Sep 16 '09 at 3:37




                          2




                          2





                          That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

                          – sbi
                          Sep 16 '09 at 8:56





                          That should be std::string s = ss.str(). If you want a const char*, use s.c_str(). (Note that, while syntactically correct, ss.str().c_str() will give you a const char* that points to a temporary which will will cease to exist at the end of the full expression. That hurts.)

                          – sbi
                          Sep 16 '09 at 8:56




                          1




                          1





                          why not just use string.append?

                          – Baiyan Huang
                          Jun 27 '14 at 9:56





                          why not just use string.append?

                          – Baiyan Huang
                          Jun 27 '14 at 9:56




                          11




                          11





                          answer is incomplete without #include <sstream>

                          – renadeen
                          Mar 20 '16 at 20:02





                          answer is incomplete without #include <sstream>

                          – renadeen
                          Mar 20 '16 at 20:02













                          42














                          Using std::copy and std::ostream_iterator we can get something as elegant as python.



                          #include <iostream>
                          #include <sstream>
                          #include <algorithm>
                          #include <iterator>


                          int main()
                          {
                          int array = {1,2,3,4};

                          std::copy(array, array+4, std::ostream_iterator<int>(std::cout,","));
                          }


                          See this question for a little class I wrote. This will not print the trailing comma. Also if we assume that C++14 will continue to give us range based equivalents of algorithms like this:



                          namespace std {
                          // I am assuming something like this in the C++14 standard
                          // I have no idea if this is correct but it should be trivial to write if it does not appear.
                          template<typename C, typename I>
                          void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
                          }
                          using POI = PrefexOutputIterator;
                          int main()
                          {
                          int array = {1,2,3,4};
                          std::copy(array, POI(std::cout, ","));
                          // ",".join(map(str,array)) // closer
                          }





                          share|improve this answer





















                          • 11





                            I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

                            – 1800 INFORMATION
                            Sep 16 '09 at 4:13






                          • 2





                            Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

                            – Martin York
                            Sep 16 '09 at 4:36






                          • 19





                            Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

                            – Steve Jessop
                            Sep 16 '09 at 10:19











                          • Why doesn't it work?

                            – jalf
                            Sep 16 '09 at 12:31






                          • 1





                            You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

                            – Dan
                            Sep 16 '09 at 15:59
















                          42














                          Using std::copy and std::ostream_iterator we can get something as elegant as python.



                          #include <iostream>
                          #include <sstream>
                          #include <algorithm>
                          #include <iterator>


                          int main()
                          {
                          int array = {1,2,3,4};

                          std::copy(array, array+4, std::ostream_iterator<int>(std::cout,","));
                          }


                          See this question for a little class I wrote. This will not print the trailing comma. Also if we assume that C++14 will continue to give us range based equivalents of algorithms like this:



                          namespace std {
                          // I am assuming something like this in the C++14 standard
                          // I have no idea if this is correct but it should be trivial to write if it does not appear.
                          template<typename C, typename I>
                          void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
                          }
                          using POI = PrefexOutputIterator;
                          int main()
                          {
                          int array = {1,2,3,4};
                          std::copy(array, POI(std::cout, ","));
                          // ",".join(map(str,array)) // closer
                          }





                          share|improve this answer





















                          • 11





                            I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

                            – 1800 INFORMATION
                            Sep 16 '09 at 4:13






                          • 2





                            Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

                            – Martin York
                            Sep 16 '09 at 4:36






                          • 19





                            Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

                            – Steve Jessop
                            Sep 16 '09 at 10:19











                          • Why doesn't it work?

                            – jalf
                            Sep 16 '09 at 12:31






                          • 1





                            You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

                            – Dan
                            Sep 16 '09 at 15:59














                          42












                          42








                          42







                          Using std::copy and std::ostream_iterator we can get something as elegant as python.



                          #include <iostream>
                          #include <sstream>
                          #include <algorithm>
                          #include <iterator>


                          int main()
                          {
                          int array = {1,2,3,4};

                          std::copy(array, array+4, std::ostream_iterator<int>(std::cout,","));
                          }


                          See this question for a little class I wrote. This will not print the trailing comma. Also if we assume that C++14 will continue to give us range based equivalents of algorithms like this:



                          namespace std {
                          // I am assuming something like this in the C++14 standard
                          // I have no idea if this is correct but it should be trivial to write if it does not appear.
                          template<typename C, typename I>
                          void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
                          }
                          using POI = PrefexOutputIterator;
                          int main()
                          {
                          int array = {1,2,3,4};
                          std::copy(array, POI(std::cout, ","));
                          // ",".join(map(str,array)) // closer
                          }





                          share|improve this answer















                          Using std::copy and std::ostream_iterator we can get something as elegant as python.



                          #include <iostream>
                          #include <sstream>
                          #include <algorithm>
                          #include <iterator>


                          int main()
                          {
                          int array = {1,2,3,4};

                          std::copy(array, array+4, std::ostream_iterator<int>(std::cout,","));
                          }


                          See this question for a little class I wrote. This will not print the trailing comma. Also if we assume that C++14 will continue to give us range based equivalents of algorithms like this:



                          namespace std {
                          // I am assuming something like this in the C++14 standard
                          // I have no idea if this is correct but it should be trivial to write if it does not appear.
                          template<typename C, typename I>
                          void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
                          }
                          using POI = PrefexOutputIterator;
                          int main()
                          {
                          int array = {1,2,3,4};
                          std::copy(array, POI(std::cout, ","));
                          // ",".join(map(str,array)) // closer
                          }






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Apr 13 '17 at 12:40









                          Community

                          11




                          11










                          answered Sep 16 '09 at 4:09









                          Martin YorkMartin York

                          201k67270487




                          201k67270487








                          • 11





                            I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

                            – 1800 INFORMATION
                            Sep 16 '09 at 4:13






                          • 2





                            Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

                            – Martin York
                            Sep 16 '09 at 4:36






                          • 19





                            Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

                            – Steve Jessop
                            Sep 16 '09 at 10:19











                          • Why doesn't it work?

                            – jalf
                            Sep 16 '09 at 12:31






                          • 1





                            You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

                            – Dan
                            Sep 16 '09 at 15:59














                          • 11





                            I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

                            – 1800 INFORMATION
                            Sep 16 '09 at 4:13






                          • 2





                            Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

                            – Martin York
                            Sep 16 '09 at 4:36






                          • 19





                            Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

                            – Steve Jessop
                            Sep 16 '09 at 10:19











                          • Why doesn't it work?

                            – jalf
                            Sep 16 '09 at 12:31






                          • 1





                            You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

                            – Dan
                            Sep 16 '09 at 15:59








                          11




                          11





                          I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

                          – 1800 INFORMATION
                          Sep 16 '09 at 4:13





                          I think this is not quite equivalent to Python's join - it will insert an extra "," at the end.

                          – 1800 INFORMATION
                          Sep 16 '09 at 4:13




                          2




                          2





                          Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

                          – Martin York
                          Sep 16 '09 at 4:36





                          Not equivalent but just as elegant (in fact I think more so but that is just an opinion).

                          – Martin York
                          Sep 16 '09 at 4:36




                          19




                          19





                          Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

                          – Steve Jessop
                          Sep 16 '09 at 10:19





                          Obviously elegance is subjective. So if you and two other people prefer longer, more repetitive code that doesn't work, then it's more elegant ;-p

                          – Steve Jessop
                          Sep 16 '09 at 10:19













                          Why doesn't it work?

                          – jalf
                          Sep 16 '09 at 12:31





                          Why doesn't it work?

                          – jalf
                          Sep 16 '09 at 12:31




                          1




                          1





                          You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

                          – Dan
                          Sep 16 '09 at 15:59





                          You can ignore the final comma by using the string::substr member function. Assign the the substring from 0 to n-1 to your result variable.

                          – Dan
                          Sep 16 '09 at 15:59











                          16














                          Another alternative is the use of std::copy and the ostream_iterator class:



                          #include <iterator>  // ostream_iterator
                          #include <sstream> // ostringstream
                          #include <algorithm> // copy

                          std::ostringstream stream;
                          std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
                          std::string s=stream.str();
                          s.erase(s.length()-1);


                          Also not as nice as Python.
                          For this purpose, I created a join function:



                          template <class T, class A>
                          T join(const A &begin, const A &end, const T &t)
                          {
                          T result;
                          for (A it=begin;
                          it!=end;
                          it++)
                          {
                          if (!result.empty())
                          result.append(t);
                          result.append(*it);
                          }
                          return result;
                          }


                          Then used it like this:



                          std::string s=join(array.begin(), array.end(), std::string(","));


                          You might ask why I passed in the iterators. Well, actually I wanted to reverse the array, so I used it like this:



                          std::string s=join(array.rbegin(), array.rend(), std::string(","));


                          Ideally, I would like to template out to the point where it can infer the char type, and use string-streams, but I couldn't figure that out yet.






                          share|improve this answer


























                          • Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

                            – sbi
                            Sep 16 '09 at 9:51











                          • Your join function can be used with vectors as well? May you please give example, I'm new to C++.

                            – Noitidart
                            Jan 15 '17 at 1:09











                          • Can you change the iterator to a preincrement in the answer?

                            – Millie Smith
                            Sep 8 '17 at 3:12


















                          16














                          Another alternative is the use of std::copy and the ostream_iterator class:



                          #include <iterator>  // ostream_iterator
                          #include <sstream> // ostringstream
                          #include <algorithm> // copy

                          std::ostringstream stream;
                          std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
                          std::string s=stream.str();
                          s.erase(s.length()-1);


                          Also not as nice as Python.
                          For this purpose, I created a join function:



                          template <class T, class A>
                          T join(const A &begin, const A &end, const T &t)
                          {
                          T result;
                          for (A it=begin;
                          it!=end;
                          it++)
                          {
                          if (!result.empty())
                          result.append(t);
                          result.append(*it);
                          }
                          return result;
                          }


                          Then used it like this:



                          std::string s=join(array.begin(), array.end(), std::string(","));


                          You might ask why I passed in the iterators. Well, actually I wanted to reverse the array, so I used it like this:



                          std::string s=join(array.rbegin(), array.rend(), std::string(","));


                          Ideally, I would like to template out to the point where it can infer the char type, and use string-streams, but I couldn't figure that out yet.






                          share|improve this answer


























                          • Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

                            – sbi
                            Sep 16 '09 at 9:51











                          • Your join function can be used with vectors as well? May you please give example, I'm new to C++.

                            – Noitidart
                            Jan 15 '17 at 1:09











                          • Can you change the iterator to a preincrement in the answer?

                            – Millie Smith
                            Sep 8 '17 at 3:12
















                          16












                          16








                          16







                          Another alternative is the use of std::copy and the ostream_iterator class:



                          #include <iterator>  // ostream_iterator
                          #include <sstream> // ostringstream
                          #include <algorithm> // copy

                          std::ostringstream stream;
                          std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
                          std::string s=stream.str();
                          s.erase(s.length()-1);


                          Also not as nice as Python.
                          For this purpose, I created a join function:



                          template <class T, class A>
                          T join(const A &begin, const A &end, const T &t)
                          {
                          T result;
                          for (A it=begin;
                          it!=end;
                          it++)
                          {
                          if (!result.empty())
                          result.append(t);
                          result.append(*it);
                          }
                          return result;
                          }


                          Then used it like this:



                          std::string s=join(array.begin(), array.end(), std::string(","));


                          You might ask why I passed in the iterators. Well, actually I wanted to reverse the array, so I used it like this:



                          std::string s=join(array.rbegin(), array.rend(), std::string(","));


                          Ideally, I would like to template out to the point where it can infer the char type, and use string-streams, but I couldn't figure that out yet.






                          share|improve this answer















                          Another alternative is the use of std::copy and the ostream_iterator class:



                          #include <iterator>  // ostream_iterator
                          #include <sstream> // ostringstream
                          #include <algorithm> // copy

                          std::ostringstream stream;
                          std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
                          std::string s=stream.str();
                          s.erase(s.length()-1);


                          Also not as nice as Python.
                          For this purpose, I created a join function:



                          template <class T, class A>
                          T join(const A &begin, const A &end, const T &t)
                          {
                          T result;
                          for (A it=begin;
                          it!=end;
                          it++)
                          {
                          if (!result.empty())
                          result.append(t);
                          result.append(*it);
                          }
                          return result;
                          }


                          Then used it like this:



                          std::string s=join(array.begin(), array.end(), std::string(","));


                          You might ask why I passed in the iterators. Well, actually I wanted to reverse the array, so I used it like this:



                          std::string s=join(array.rbegin(), array.rend(), std::string(","));


                          Ideally, I would like to template out to the point where it can infer the char type, and use string-streams, but I couldn't figure that out yet.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Apr 20 '15 at 10:18









                          user1556814

                          119111




                          119111










                          answered Sep 16 '09 at 4:09









                          1800 INFORMATION1800 INFORMATION

                          100k23138224




                          100k23138224













                          • Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

                            – sbi
                            Sep 16 '09 at 9:51











                          • Your join function can be used with vectors as well? May you please give example, I'm new to C++.

                            – Noitidart
                            Jan 15 '17 at 1:09











                          • Can you change the iterator to a preincrement in the answer?

                            – Millie Smith
                            Sep 8 '17 at 3:12





















                          • Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

                            – sbi
                            Sep 16 '09 at 9:51











                          • Your join function can be used with vectors as well? May you please give example, I'm new to C++.

                            – Noitidart
                            Jan 15 '17 at 1:09











                          • Can you change the iterator to a preincrement in the answer?

                            – Millie Smith
                            Sep 8 '17 at 3:12



















                          Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

                          – sbi
                          Sep 16 '09 at 9:51





                          Since it would be too much for a comment, I have posted an answer (stackoverflow.com/questions/1430757/1432040#1432040) which attempts to solve the riddle given in your last sentence.

                          – sbi
                          Sep 16 '09 at 9:51













                          Your join function can be used with vectors as well? May you please give example, I'm new to C++.

                          – Noitidart
                          Jan 15 '17 at 1:09





                          Your join function can be used with vectors as well? May you please give example, I'm new to C++.

                          – Noitidart
                          Jan 15 '17 at 1:09













                          Can you change the iterator to a preincrement in the answer?

                          – Millie Smith
                          Sep 8 '17 at 3:12







                          Can you change the iterator to a preincrement in the answer?

                          – Millie Smith
                          Sep 8 '17 at 3:12













                          16














                          You can use std::accumulate. Consider the following example



                          if (v.empty() 
                          return std::string();
                          std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
                          (const std::string& a, int b){
                          return a + ',' + std::to_string(b);
                          });





                          share|improve this answer




























                            16














                            You can use std::accumulate. Consider the following example



                            if (v.empty() 
                            return std::string();
                            std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
                            (const std::string& a, int b){
                            return a + ',' + std::to_string(b);
                            });





                            share|improve this answer


























                              16












                              16








                              16







                              You can use std::accumulate. Consider the following example



                              if (v.empty() 
                              return std::string();
                              std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
                              (const std::string& a, int b){
                              return a + ',' + std::to_string(b);
                              });





                              share|improve this answer













                              You can use std::accumulate. Consider the following example



                              if (v.empty() 
                              return std::string();
                              std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
                              (const std::string& a, int b){
                              return a + ',' + std::to_string(b);
                              });






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered May 31 '15 at 11:06









                              caponecapone

                              398214




                              398214























                                  12














                                  With Boost and C++11 this could be achieved like this:



                                  auto array = {1,2,3,4};
                                  join(array | transformed(tostr), ",");


                                  Well, almost. Here's the full example:



                                  #include <array>
                                  #include <iostream>

                                  #include <boost/algorithm/string/join.hpp>
                                  #include <boost/range/adaptor/transformed.hpp>

                                  int main() {
                                  using boost::algorithm::join;
                                  using boost::adaptors::transformed;
                                  auto tostr = static_cast<std::string(*)(int)>(std::to_string);

                                  auto array = {1,2,3,4};
                                  std::cout << join(array | transformed(tostr), ",") << std::endl;

                                  return 0;
                                  }


                                  Credit to Praetorian.



                                  You can handle any value type like this:



                                  template<class Container>
                                  std::string join(Container const & container, std::string delimiter) {
                                  using boost::algorithm::join;
                                  using boost::adaptors::transformed;
                                  using value_type = typename Container::value_type;

                                  auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
                                  return join(container | transformed(tostr), delimiter);
                                  };





                                  share|improve this answer






























                                    12














                                    With Boost and C++11 this could be achieved like this:



                                    auto array = {1,2,3,4};
                                    join(array | transformed(tostr), ",");


                                    Well, almost. Here's the full example:



                                    #include <array>
                                    #include <iostream>

                                    #include <boost/algorithm/string/join.hpp>
                                    #include <boost/range/adaptor/transformed.hpp>

                                    int main() {
                                    using boost::algorithm::join;
                                    using boost::adaptors::transformed;
                                    auto tostr = static_cast<std::string(*)(int)>(std::to_string);

                                    auto array = {1,2,3,4};
                                    std::cout << join(array | transformed(tostr), ",") << std::endl;

                                    return 0;
                                    }


                                    Credit to Praetorian.



                                    You can handle any value type like this:



                                    template<class Container>
                                    std::string join(Container const & container, std::string delimiter) {
                                    using boost::algorithm::join;
                                    using boost::adaptors::transformed;
                                    using value_type = typename Container::value_type;

                                    auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
                                    return join(container | transformed(tostr), delimiter);
                                    };





                                    share|improve this answer




























                                      12












                                      12








                                      12







                                      With Boost and C++11 this could be achieved like this:



                                      auto array = {1,2,3,4};
                                      join(array | transformed(tostr), ",");


                                      Well, almost. Here's the full example:



                                      #include <array>
                                      #include <iostream>

                                      #include <boost/algorithm/string/join.hpp>
                                      #include <boost/range/adaptor/transformed.hpp>

                                      int main() {
                                      using boost::algorithm::join;
                                      using boost::adaptors::transformed;
                                      auto tostr = static_cast<std::string(*)(int)>(std::to_string);

                                      auto array = {1,2,3,4};
                                      std::cout << join(array | transformed(tostr), ",") << std::endl;

                                      return 0;
                                      }


                                      Credit to Praetorian.



                                      You can handle any value type like this:



                                      template<class Container>
                                      std::string join(Container const & container, std::string delimiter) {
                                      using boost::algorithm::join;
                                      using boost::adaptors::transformed;
                                      using value_type = typename Container::value_type;

                                      auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
                                      return join(container | transformed(tostr), delimiter);
                                      };





                                      share|improve this answer















                                      With Boost and C++11 this could be achieved like this:



                                      auto array = {1,2,3,4};
                                      join(array | transformed(tostr), ",");


                                      Well, almost. Here's the full example:



                                      #include <array>
                                      #include <iostream>

                                      #include <boost/algorithm/string/join.hpp>
                                      #include <boost/range/adaptor/transformed.hpp>

                                      int main() {
                                      using boost::algorithm::join;
                                      using boost::adaptors::transformed;
                                      auto tostr = static_cast<std::string(*)(int)>(std::to_string);

                                      auto array = {1,2,3,4};
                                      std::cout << join(array | transformed(tostr), ",") << std::endl;

                                      return 0;
                                      }


                                      Credit to Praetorian.



                                      You can handle any value type like this:



                                      template<class Container>
                                      std::string join(Container const & container, std::string delimiter) {
                                      using boost::algorithm::join;
                                      using boost::adaptors::transformed;
                                      using value_type = typename Container::value_type;

                                      auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
                                      return join(container | transformed(tostr), delimiter);
                                      };






                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited May 23 '17 at 11:33









                                      Community

                                      11




                                      11










                                      answered Oct 6 '15 at 14:25









                                      arekolekarekolek

                                      4,6213250




                                      4,6213250























                                          10














                                          This is just an attempt to solve the riddle given by 1800 INFORMATION's remark on his second solution lacking genericity, not an attempt to answer the question:



                                          template <class Str, class It>
                                          Str join(It begin, const It end, const Str &sep)
                                          {
                                          typedef typename Str::value_type char_type;
                                          typedef typename Str::traits_type traits_type;
                                          typedef typename Str::allocator_type allocator_type;
                                          typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
                                          ostringstream_type;
                                          ostringstream_type result;

                                          if(begin!=end)
                                          result << *begin++;
                                          while(begin!=end) {
                                          result << sep;
                                          result << *begin++;
                                          }
                                          return result.str();
                                          }


                                          Works On My Machine(TM).






                                          share|improve this answer


























                                          • Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

                                            – Grault
                                            Apr 9 '15 at 4:01











                                          • @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

                                            – sbi
                                            Apr 9 '15 at 4:46











                                          • I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

                                            – Grault
                                            Apr 11 '15 at 2:52













                                          • @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

                                            – sbi
                                            Apr 11 '15 at 7:41











                                          • Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

                                            – zett42
                                            Sep 26 '18 at 19:58


















                                          10














                                          This is just an attempt to solve the riddle given by 1800 INFORMATION's remark on his second solution lacking genericity, not an attempt to answer the question:



                                          template <class Str, class It>
                                          Str join(It begin, const It end, const Str &sep)
                                          {
                                          typedef typename Str::value_type char_type;
                                          typedef typename Str::traits_type traits_type;
                                          typedef typename Str::allocator_type allocator_type;
                                          typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
                                          ostringstream_type;
                                          ostringstream_type result;

                                          if(begin!=end)
                                          result << *begin++;
                                          while(begin!=end) {
                                          result << sep;
                                          result << *begin++;
                                          }
                                          return result.str();
                                          }


                                          Works On My Machine(TM).






                                          share|improve this answer


























                                          • Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

                                            – Grault
                                            Apr 9 '15 at 4:01











                                          • @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

                                            – sbi
                                            Apr 9 '15 at 4:46











                                          • I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

                                            – Grault
                                            Apr 11 '15 at 2:52













                                          • @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

                                            – sbi
                                            Apr 11 '15 at 7:41











                                          • Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

                                            – zett42
                                            Sep 26 '18 at 19:58
















                                          10












                                          10








                                          10







                                          This is just an attempt to solve the riddle given by 1800 INFORMATION's remark on his second solution lacking genericity, not an attempt to answer the question:



                                          template <class Str, class It>
                                          Str join(It begin, const It end, const Str &sep)
                                          {
                                          typedef typename Str::value_type char_type;
                                          typedef typename Str::traits_type traits_type;
                                          typedef typename Str::allocator_type allocator_type;
                                          typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
                                          ostringstream_type;
                                          ostringstream_type result;

                                          if(begin!=end)
                                          result << *begin++;
                                          while(begin!=end) {
                                          result << sep;
                                          result << *begin++;
                                          }
                                          return result.str();
                                          }


                                          Works On My Machine(TM).






                                          share|improve this answer















                                          This is just an attempt to solve the riddle given by 1800 INFORMATION's remark on his second solution lacking genericity, not an attempt to answer the question:



                                          template <class Str, class It>
                                          Str join(It begin, const It end, const Str &sep)
                                          {
                                          typedef typename Str::value_type char_type;
                                          typedef typename Str::traits_type traits_type;
                                          typedef typename Str::allocator_type allocator_type;
                                          typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
                                          ostringstream_type;
                                          ostringstream_type result;

                                          if(begin!=end)
                                          result << *begin++;
                                          while(begin!=end) {
                                          result << sep;
                                          result << *begin++;
                                          }
                                          return result.str();
                                          }


                                          Works On My Machine(TM).







                                          share|improve this answer














                                          share|improve this answer



                                          share|improve this answer








                                          edited May 23 '17 at 12:03









                                          Community

                                          11




                                          11










                                          answered Sep 16 '09 at 9:50









                                          sbisbi

                                          168k41218403




                                          168k41218403













                                          • Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

                                            – Grault
                                            Apr 9 '15 at 4:01











                                          • @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

                                            – sbi
                                            Apr 9 '15 at 4:46











                                          • I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

                                            – Grault
                                            Apr 11 '15 at 2:52













                                          • @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

                                            – sbi
                                            Apr 11 '15 at 7:41











                                          • Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

                                            – zett42
                                            Sep 26 '18 at 19:58





















                                          • Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

                                            – Grault
                                            Apr 9 '15 at 4:01











                                          • @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

                                            – sbi
                                            Apr 9 '15 at 4:46











                                          • I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

                                            – Grault
                                            Apr 11 '15 at 2:52













                                          • @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

                                            – sbi
                                            Apr 11 '15 at 7:41











                                          • Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

                                            – zett42
                                            Sep 26 '18 at 19:58



















                                          Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

                                          – Grault
                                          Apr 9 '15 at 4:01





                                          Visual Studio 2013 gets very confused by the typedefs. Not that you could have known that in 2009.

                                          – Grault
                                          Apr 9 '15 at 4:01













                                          @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

                                          – sbi
                                          Apr 9 '15 at 4:46





                                          @Jes: I have now been staring at this for 5mins, but couldn't figure out what VS might trip over. Can you be more specific?

                                          – sbi
                                          Apr 9 '15 at 4:46













                                          I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

                                          – Grault
                                          Apr 11 '15 at 2:52







                                          I'm sorry, I think I had attempted a join of objects without << overloads, which I now realize is inappropriate for your code. I cannot cause your code to not compile with a vector of strings. On a side note, VS 2013 Community is both free and feature-ful, unlike "Express" versions.

                                          – Grault
                                          Apr 11 '15 at 2:52















                                          @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

                                          – sbi
                                          Apr 11 '15 at 7:41





                                          @Jes: This should work with any type that can be streamed (i.e., has operator<< overloaded). Of course, a type without operator<< might cause very confusing error messages.

                                          – sbi
                                          Apr 11 '15 at 7:41













                                          Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

                                          – zett42
                                          Sep 26 '18 at 19:58







                                          Unfortunately, this doesn't compile: join(v.begin(), v.end(), ","). Template argument deduction doesn't produce the right result if the sep argument is a string literal. My attempt at a solution for this issue. Also providing a more modern range-based overload.

                                          – zett42
                                          Sep 26 '18 at 19:58













                                          7














                                          Lots of template/ideas. Mine's not as generic or efficient, but I just had the same problem and wanted to throw this into the mix as something short and sweet. It wins on shortest number of lines... :)



                                          std::stringstream joinedValues;
                                          for (auto value: array)
                                          {
                                          joinedValues << value << ",";
                                          }
                                          //Strip off the trailing comma
                                          std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);





                                          share|improve this answer



















                                          • 1





                                            Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

                                            – Millie Smith
                                            Sep 8 '17 at 4:31











                                          • Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

                                            – ifyalciner
                                            Dec 7 '17 at 23:31
















                                          7














                                          Lots of template/ideas. Mine's not as generic or efficient, but I just had the same problem and wanted to throw this into the mix as something short and sweet. It wins on shortest number of lines... :)



                                          std::stringstream joinedValues;
                                          for (auto value: array)
                                          {
                                          joinedValues << value << ",";
                                          }
                                          //Strip off the trailing comma
                                          std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);





                                          share|improve this answer



















                                          • 1





                                            Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

                                            – Millie Smith
                                            Sep 8 '17 at 4:31











                                          • Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

                                            – ifyalciner
                                            Dec 7 '17 at 23:31














                                          7












                                          7








                                          7







                                          Lots of template/ideas. Mine's not as generic or efficient, but I just had the same problem and wanted to throw this into the mix as something short and sweet. It wins on shortest number of lines... :)



                                          std::stringstream joinedValues;
                                          for (auto value: array)
                                          {
                                          joinedValues << value << ",";
                                          }
                                          //Strip off the trailing comma
                                          std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);





                                          share|improve this answer













                                          Lots of template/ideas. Mine's not as generic or efficient, but I just had the same problem and wanted to throw this into the mix as something short and sweet. It wins on shortest number of lines... :)



                                          std::stringstream joinedValues;
                                          for (auto value: array)
                                          {
                                          joinedValues << value << ",";
                                          }
                                          //Strip off the trailing comma
                                          std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);






                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          answered May 1 '14 at 18:48









                                          Joe SchneiderJoe Schneider

                                          5,32473457




                                          5,32473457








                                          • 1





                                            Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

                                            – Millie Smith
                                            Sep 8 '17 at 4:31











                                          • Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

                                            – ifyalciner
                                            Dec 7 '17 at 23:31














                                          • 1





                                            Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

                                            – Millie Smith
                                            Sep 8 '17 at 4:31











                                          • Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

                                            – ifyalciner
                                            Dec 7 '17 at 23:31








                                          1




                                          1





                                          Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

                                          – Millie Smith
                                          Sep 8 '17 at 4:31





                                          Thanks for the simplistic code. Might want to change it to "auto &" though to avoid the extra copies and get some easy performance gains.

                                          – Millie Smith
                                          Sep 8 '17 at 4:31













                                          Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

                                          – ifyalciner
                                          Dec 7 '17 at 23:31





                                          Instead of using substr(...), use pop_back() to remove last character, becomes much more clear and clean then.

                                          – ifyalciner
                                          Dec 7 '17 at 23:31











                                          4














                                          If you want to do std::cout << join(myVector, ",") << std::endl;, you can do something like:



                                          template <typename C, typename T> class MyJoiner
                                          {
                                          C &c;
                                          T &s;
                                          MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
                                          public:
                                          template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
                                          template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
                                          };

                                          template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
                                          {
                                          auto i = mj.c.begin();
                                          if (i != mj.c.end())
                                          {
                                          o << *i++;
                                          while (i != mj.c.end())
                                          {
                                          o << mj.s << *i++;
                                          }
                                          }

                                          return o;
                                          }

                                          template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
                                          {
                                          return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
                                          }


                                          Note, this solution does the join directly into the output stream rather than creating a secondary buffer and will work with any types that have an operator<< onto an ostream.



                                          This also works where boost::algorithm::join() fails, when you have a vector<char*> instead of a vector<string>.






                                          share|improve this answer




























                                            4














                                            If you want to do std::cout << join(myVector, ",") << std::endl;, you can do something like:



                                            template <typename C, typename T> class MyJoiner
                                            {
                                            C &c;
                                            T &s;
                                            MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
                                            public:
                                            template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
                                            template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
                                            };

                                            template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
                                            {
                                            auto i = mj.c.begin();
                                            if (i != mj.c.end())
                                            {
                                            o << *i++;
                                            while (i != mj.c.end())
                                            {
                                            o << mj.s << *i++;
                                            }
                                            }

                                            return o;
                                            }

                                            template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
                                            {
                                            return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
                                            }


                                            Note, this solution does the join directly into the output stream rather than creating a secondary buffer and will work with any types that have an operator<< onto an ostream.



                                            This also works where boost::algorithm::join() fails, when you have a vector<char*> instead of a vector<string>.






                                            share|improve this answer


























                                              4












                                              4








                                              4







                                              If you want to do std::cout << join(myVector, ",") << std::endl;, you can do something like:



                                              template <typename C, typename T> class MyJoiner
                                              {
                                              C &c;
                                              T &s;
                                              MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
                                              public:
                                              template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
                                              template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
                                              };

                                              template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
                                              {
                                              auto i = mj.c.begin();
                                              if (i != mj.c.end())
                                              {
                                              o << *i++;
                                              while (i != mj.c.end())
                                              {
                                              o << mj.s << *i++;
                                              }
                                              }

                                              return o;
                                              }

                                              template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
                                              {
                                              return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
                                              }


                                              Note, this solution does the join directly into the output stream rather than creating a secondary buffer and will work with any types that have an operator<< onto an ostream.



                                              This also works where boost::algorithm::join() fails, when you have a vector<char*> instead of a vector<string>.






                                              share|improve this answer













                                              If you want to do std::cout << join(myVector, ",") << std::endl;, you can do something like:



                                              template <typename C, typename T> class MyJoiner
                                              {
                                              C &c;
                                              T &s;
                                              MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
                                              public:
                                              template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
                                              template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
                                              };

                                              template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
                                              {
                                              auto i = mj.c.begin();
                                              if (i != mj.c.end())
                                              {
                                              o << *i++;
                                              while (i != mj.c.end())
                                              {
                                              o << mj.s << *i++;
                                              }
                                              }

                                              return o;
                                              }

                                              template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
                                              {
                                              return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
                                              }


                                              Note, this solution does the join directly into the output stream rather than creating a secondary buffer and will work with any types that have an operator<< onto an ostream.



                                              This also works where boost::algorithm::join() fails, when you have a vector<char*> instead of a vector<string>.







                                              share|improve this answer












                                              share|improve this answer



                                              share|improve this answer










                                              answered Jun 21 '15 at 22:59









                                              mheymanmheyman

                                              2,8732728




                                              2,8732728























                                                  2














                                                  I like 1800's answer. However I would move the first iteration out of the loop as as the result of the if statement only changes once after the first iteration



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  {
                                                  result.append(*it);
                                                  ++it;
                                                  }

                                                  for( ;
                                                  it!=end;
                                                  ++it)
                                                  {
                                                  result.append(t);
                                                  result.append(*it);
                                                  }
                                                  return result;
                                                  }


                                                  This can of course be reduced down to fewer statements if you like:



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  result.append(*it++);

                                                  for( ; it!=end; ++it)
                                                  result.append(t).append(*it);
                                                  return result;
                                                  }





                                                  share|improve this answer


























                                                  • You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

                                                    – sbi
                                                    Sep 16 '09 at 19:29











                                                  • Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

                                                    – iain
                                                    Sep 17 '09 at 13:12











                                                  • Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

                                                    – iain
                                                    Sep 17 '09 at 13:20






                                                  • 1





                                                    @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

                                                    – sbi
                                                    Sep 17 '09 at 14:50






                                                  • 1





                                                    @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

                                                    – iain
                                                    Sep 18 '09 at 9:50
















                                                  2














                                                  I like 1800's answer. However I would move the first iteration out of the loop as as the result of the if statement only changes once after the first iteration



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  {
                                                  result.append(*it);
                                                  ++it;
                                                  }

                                                  for( ;
                                                  it!=end;
                                                  ++it)
                                                  {
                                                  result.append(t);
                                                  result.append(*it);
                                                  }
                                                  return result;
                                                  }


                                                  This can of course be reduced down to fewer statements if you like:



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  result.append(*it++);

                                                  for( ; it!=end; ++it)
                                                  result.append(t).append(*it);
                                                  return result;
                                                  }





                                                  share|improve this answer


























                                                  • You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

                                                    – sbi
                                                    Sep 16 '09 at 19:29











                                                  • Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

                                                    – iain
                                                    Sep 17 '09 at 13:12











                                                  • Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

                                                    – iain
                                                    Sep 17 '09 at 13:20






                                                  • 1





                                                    @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

                                                    – sbi
                                                    Sep 17 '09 at 14:50






                                                  • 1





                                                    @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

                                                    – iain
                                                    Sep 18 '09 at 9:50














                                                  2












                                                  2








                                                  2







                                                  I like 1800's answer. However I would move the first iteration out of the loop as as the result of the if statement only changes once after the first iteration



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  {
                                                  result.append(*it);
                                                  ++it;
                                                  }

                                                  for( ;
                                                  it!=end;
                                                  ++it)
                                                  {
                                                  result.append(t);
                                                  result.append(*it);
                                                  }
                                                  return result;
                                                  }


                                                  This can of course be reduced down to fewer statements if you like:



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  result.append(*it++);

                                                  for( ; it!=end; ++it)
                                                  result.append(t).append(*it);
                                                  return result;
                                                  }





                                                  share|improve this answer















                                                  I like 1800's answer. However I would move the first iteration out of the loop as as the result of the if statement only changes once after the first iteration



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  {
                                                  result.append(*it);
                                                  ++it;
                                                  }

                                                  for( ;
                                                  it!=end;
                                                  ++it)
                                                  {
                                                  result.append(t);
                                                  result.append(*it);
                                                  }
                                                  return result;
                                                  }


                                                  This can of course be reduced down to fewer statements if you like:



                                                  template <class T, class A>
                                                  T join(const A &begin, const A &end, const T &t)
                                                  {
                                                  T result;
                                                  A it = begin;
                                                  if (it != end)
                                                  result.append(*it++);

                                                  for( ; it!=end; ++it)
                                                  result.append(t).append(*it);
                                                  return result;
                                                  }






                                                  share|improve this answer














                                                  share|improve this answer



                                                  share|improve this answer








                                                  edited Sep 17 '09 at 13:20

























                                                  answered Sep 16 '09 at 10:23









                                                  iainiain

                                                  8,98232937




                                                  8,98232937













                                                  • You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

                                                    – sbi
                                                    Sep 16 '09 at 19:29











                                                  • Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

                                                    – iain
                                                    Sep 17 '09 at 13:12











                                                  • Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

                                                    – iain
                                                    Sep 17 '09 at 13:20






                                                  • 1





                                                    @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

                                                    – sbi
                                                    Sep 17 '09 at 14:50






                                                  • 1





                                                    @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

                                                    – iain
                                                    Sep 18 '09 at 9:50



















                                                  • You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

                                                    – sbi
                                                    Sep 16 '09 at 19:29











                                                  • Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

                                                    – iain
                                                    Sep 17 '09 at 13:12











                                                  • Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

                                                    – iain
                                                    Sep 17 '09 at 13:20






                                                  • 1





                                                    @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

                                                    – sbi
                                                    Sep 17 '09 at 14:50






                                                  • 1





                                                    @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

                                                    – iain
                                                    Sep 18 '09 at 9:50

















                                                  You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

                                                  – sbi
                                                  Sep 16 '09 at 19:29





                                                  You shouldn't use post-increment for unknown iterator types. That might be expensive. (Of course, when dealing with strings, that might not make that much of a difference. But once you learn the habit...)

                                                  – sbi
                                                  Sep 16 '09 at 19:29













                                                  Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

                                                  – iain
                                                  Sep 17 '09 at 13:12





                                                  Post increment is fine as long as you use the tempory value that is returned. eg "result.append(*it); ++it;" is almost always as expensive as "result.append(*it++);" the second has one extra copy of the iterator.

                                                  – iain
                                                  Sep 17 '09 at 13:12













                                                  Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

                                                  – iain
                                                  Sep 17 '09 at 13:20





                                                  Oops I just spotted the post increment in the for loop. copy and paste error. I have fixed the post.

                                                  – iain
                                                  Sep 17 '09 at 13:20




                                                  1




                                                  1





                                                  @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

                                                  – sbi
                                                  Sep 17 '09 at 14:50





                                                  @Ian: When I taught C++, I hammered into my students to use ++i except where they really needed i++ because that was the only way they wouldn't forget this when it made a difference. (It was the same with me, BTW.) They had learned Java before, where all kinds of C-isms are en vogue and it took them a few months (1 lecture +lab work per week), but in the end most of them learned the habit to use pre-increment.

                                                  – sbi
                                                  Sep 17 '09 at 14:50




                                                  1




                                                  1





                                                  @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

                                                  – iain
                                                  Sep 18 '09 at 9:50





                                                  @sbi: agreed I always default to preincrement too, the rogue postincrement came from copying someone elses for loop and changing it. In my first reply I thought you were worried about "result.append(*it++)" and not the for loop. I was a little embarrassed to see the post increment in the loop. Some people seem to follow the advice of not using post increment too far and never use it or change it even when it is appropriate. However I know now you don't fall in to this category.

                                                  – iain
                                                  Sep 18 '09 at 9:50











                                                  2














                                                  There are some interesting attempts at providing an elegant solution to the problem. I had an idea to use templated streams to effectively answer the OP's original dilemma. Though this is an old post, I'm hoping future users who stumble upon this will find my solution beneficial.



                                                  First, some answers (including the accepted answer) do not promote re-usability. Since C++ doesn't provide an elegant way to join strings in the standard library (that I have seen), it becomes important to create one that is flexible and reusable. Here's my shot at it:



                                                  // Replace with your namespace //
                                                  namespace my {
                                                  // Templated join which can be used on any combination of streams, iterators and base types //
                                                  template <typename TStream, typename TIter, typename TSeperator>
                                                  TStream& join(TStream& stream, TIter begin, TIter end, TSeperator seperator) {
                                                  // A flag which, when true, has next iteration prepend our seperator to the stream //
                                                  bool sep = false;
                                                  // Begin iterating through our list //
                                                  for (TIter i = begin; i != end; ++i) {
                                                  // If we need to prepend a seperator, do it //
                                                  if (sep) stream << seperator;
                                                  // Stream the next value held by our iterator //
                                                  stream << *i;
                                                  // Flag that next loops needs a seperator //
                                                  sep = true;
                                                  }
                                                  // As a convenience, we return a reference to the passed stream //
                                                  return stream;
                                                  }
                                                  }


                                                  Now to use this, you could simply do something like the following:



                                                  // Load some data //
                                                  std::vector<int> params;
                                                  params.push_back(1);
                                                  params.push_back(2);
                                                  params.push_back(3);
                                                  params.push_back(4);

                                                  // Store and print our results to standard out //
                                                  std::stringstream param_stream;
                                                  std::cout << my::join(param_stream, params.begin(), params.end(), ",").str() << std::endl;

                                                  // A quick and dirty way to print directly to standard out //
                                                  my::join(std::cout, params.begin(), params.end(), ",") << std::endl;


                                                  Note how the use of streams makes this solution incredibly flexible as we can store our result in a stringstream to reclaim it later, or we can write directly to the standard out, a file, or even to a network connection implemented as a stream. The type being printed must simply be iteratable and compatible with the source stream. STL provides various streams which are compatible with a large range of types. So you could really go to town with this. Off the top of my head, your vector can be of int, float, double, string, unsigned int, SomeObject*, and more.






                                                  share|improve this answer




























                                                    2














                                                    There are some interesting attempts at providing an elegant solution to the problem. I had an idea to use templated streams to effectively answer the OP's original dilemma. Though this is an old post, I'm hoping future users who stumble upon this will find my solution beneficial.



                                                    First, some answers (including the accepted answer) do not promote re-usability. Since C++ doesn't provide an elegant way to join strings in the standard library (that I have seen), it becomes important to create one that is flexible and reusable. Here's my shot at it:



                                                    // Replace with your namespace //
                                                    namespace my {
                                                    // Templated join which can be used on any combination of streams, iterators and base types //
                                                    template <typename TStream, typename TIter, typename TSeperator>
                                                    TStream& join(TStream& stream, TIter begin, TIter end, TSeperator seperator) {
                                                    // A flag which, when true, has next iteration prepend our seperator to the stream //
                                                    bool sep = false;
                                                    // Begin iterating through our list //
                                                    for (TIter i = begin; i != end; ++i) {
                                                    // If we need to prepend a seperator, do it //
                                                    if (sep) stream << seperator;
                                                    // Stream the next value held by our iterator //
                                                    stream << *i;
                                                    // Flag that next loops needs a seperator //
                                                    sep = true;
                                                    }
                                                    // As a convenience, we return a reference to the passed stream //
                                                    return stream;
                                                    }
                                                    }


                                                    Now to use this, you could simply do something like the following:



                                                    // Load some data //
                                                    std::vector<int> params;
                                                    params.push_back(1);
                                                    params.push_back(2);
                                                    params.push_back(3);
                                                    params.push_back(4);

                                                    // Store and print our results to standard out //
                                                    std::stringstream param_stream;
                                                    std::cout << my::join(param_stream, params.begin(), params.end(), ",").str() << std::endl;

                                                    // A quick and dirty way to print directly to standard out //
                                                    my::join(std::cout, params.begin(), params.end(), ",") << std::endl;


                                                    Note how the use of streams makes this solution incredibly flexible as we can store our result in a stringstream to reclaim it later, or we can write directly to the standard out, a file, or even to a network connection implemented as a stream. The type being printed must simply be iteratable and compatible with the source stream. STL provides various streams which are compatible with a large range of types. So you could really go to town with this. Off the top of my head, your vector can be of int, float, double, string, unsigned int, SomeObject*, and more.






                                                    share|improve this answer


























                                                      2












                                                      2








                                                      2







                                                      There are some interesting attempts at providing an elegant solution to the problem. I had an idea to use templated streams to effectively answer the OP's original dilemma. Though this is an old post, I'm hoping future users who stumble upon this will find my solution beneficial.



                                                      First, some answers (including the accepted answer) do not promote re-usability. Since C++ doesn't provide an elegant way to join strings in the standard library (that I have seen), it becomes important to create one that is flexible and reusable. Here's my shot at it:



                                                      // Replace with your namespace //
                                                      namespace my {
                                                      // Templated join which can be used on any combination of streams, iterators and base types //
                                                      template <typename TStream, typename TIter, typename TSeperator>
                                                      TStream& join(TStream& stream, TIter begin, TIter end, TSeperator seperator) {
                                                      // A flag which, when true, has next iteration prepend our seperator to the stream //
                                                      bool sep = false;
                                                      // Begin iterating through our list //
                                                      for (TIter i = begin; i != end; ++i) {
                                                      // If we need to prepend a seperator, do it //
                                                      if (sep) stream << seperator;
                                                      // Stream the next value held by our iterator //
                                                      stream << *i;
                                                      // Flag that next loops needs a seperator //
                                                      sep = true;
                                                      }
                                                      // As a convenience, we return a reference to the passed stream //
                                                      return stream;
                                                      }
                                                      }


                                                      Now to use this, you could simply do something like the following:



                                                      // Load some data //
                                                      std::vector<int> params;
                                                      params.push_back(1);
                                                      params.push_back(2);
                                                      params.push_back(3);
                                                      params.push_back(4);

                                                      // Store and print our results to standard out //
                                                      std::stringstream param_stream;
                                                      std::cout << my::join(param_stream, params.begin(), params.end(), ",").str() << std::endl;

                                                      // A quick and dirty way to print directly to standard out //
                                                      my::join(std::cout, params.begin(), params.end(), ",") << std::endl;


                                                      Note how the use of streams makes this solution incredibly flexible as we can store our result in a stringstream to reclaim it later, or we can write directly to the standard out, a file, or even to a network connection implemented as a stream. The type being printed must simply be iteratable and compatible with the source stream. STL provides various streams which are compatible with a large range of types. So you could really go to town with this. Off the top of my head, your vector can be of int, float, double, string, unsigned int, SomeObject*, and more.






                                                      share|improve this answer













                                                      There are some interesting attempts at providing an elegant solution to the problem. I had an idea to use templated streams to effectively answer the OP's original dilemma. Though this is an old post, I'm hoping future users who stumble upon this will find my solution beneficial.



                                                      First, some answers (including the accepted answer) do not promote re-usability. Since C++ doesn't provide an elegant way to join strings in the standard library (that I have seen), it becomes important to create one that is flexible and reusable. Here's my shot at it:



                                                      // Replace with your namespace //
                                                      namespace my {
                                                      // Templated join which can be used on any combination of streams, iterators and base types //
                                                      template <typename TStream, typename TIter, typename TSeperator>
                                                      TStream& join(TStream& stream, TIter begin, TIter end, TSeperator seperator) {
                                                      // A flag which, when true, has next iteration prepend our seperator to the stream //
                                                      bool sep = false;
                                                      // Begin iterating through our list //
                                                      for (TIter i = begin; i != end; ++i) {
                                                      // If we need to prepend a seperator, do it //
                                                      if (sep) stream << seperator;
                                                      // Stream the next value held by our iterator //
                                                      stream << *i;
                                                      // Flag that next loops needs a seperator //
                                                      sep = true;
                                                      }
                                                      // As a convenience, we return a reference to the passed stream //
                                                      return stream;
                                                      }
                                                      }


                                                      Now to use this, you could simply do something like the following:



                                                      // Load some data //
                                                      std::vector<int> params;
                                                      params.push_back(1);
                                                      params.push_back(2);
                                                      params.push_back(3);
                                                      params.push_back(4);

                                                      // Store and print our results to standard out //
                                                      std::stringstream param_stream;
                                                      std::cout << my::join(param_stream, params.begin(), params.end(), ",").str() << std::endl;

                                                      // A quick and dirty way to print directly to standard out //
                                                      my::join(std::cout, params.begin(), params.end(), ",") << std::endl;


                                                      Note how the use of streams makes this solution incredibly flexible as we can store our result in a stringstream to reclaim it later, or we can write directly to the standard out, a file, or even to a network connection implemented as a stream. The type being printed must simply be iteratable and compatible with the source stream. STL provides various streams which are compatible with a large range of types. So you could really go to town with this. Off the top of my head, your vector can be of int, float, double, string, unsigned int, SomeObject*, and more.







                                                      share|improve this answer












                                                      share|improve this answer



                                                      share|improve this answer










                                                      answered Jul 13 '13 at 19:08









                                                      David PetersonDavid Peterson

                                                      643616




                                                      643616























                                                          2














                                                          string s;
                                                          for (auto i : v)
                                                          s += (s.empty() ? "" : ",") + to_string(i);





                                                          share|improve this answer



















                                                          • 5





                                                            Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

                                                            – paper1111
                                                            Jan 23 at 10:18











                                                          • The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

                                                            – aberaud
                                                            Feb 17 at 20:10


















                                                          2














                                                          string s;
                                                          for (auto i : v)
                                                          s += (s.empty() ? "" : ",") + to_string(i);





                                                          share|improve this answer



















                                                          • 5





                                                            Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

                                                            – paper1111
                                                            Jan 23 at 10:18











                                                          • The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

                                                            – aberaud
                                                            Feb 17 at 20:10
















                                                          2












                                                          2








                                                          2







                                                          string s;
                                                          for (auto i : v)
                                                          s += (s.empty() ? "" : ",") + to_string(i);





                                                          share|improve this answer













                                                          string s;
                                                          for (auto i : v)
                                                          s += (s.empty() ? "" : ",") + to_string(i);






                                                          share|improve this answer












                                                          share|improve this answer



                                                          share|improve this answer










                                                          answered Jan 23 at 10:17









                                                          chenfy27chenfy27

                                                          211




                                                          211








                                                          • 5





                                                            Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

                                                            – paper1111
                                                            Jan 23 at 10:18











                                                          • The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

                                                            – aberaud
                                                            Feb 17 at 20:10
















                                                          • 5





                                                            Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

                                                            – paper1111
                                                            Jan 23 at 10:18











                                                          • The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

                                                            – aberaud
                                                            Feb 17 at 20:10










                                                          5




                                                          5





                                                          Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

                                                          – paper1111
                                                          Jan 23 at 10:18





                                                          Welcome to Stack Overflow! While this code could solve the problem, it is best to add elaboration and explain how it works for people who might not understand this piece of code.

                                                          – paper1111
                                                          Jan 23 at 10:18













                                                          The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

                                                          – aberaud
                                                          Feb 17 at 20:10







                                                          The current top answer is not much more elaborate, and this is the smallest/cleanest working answer. Not as efficient as std::stringstream for large arrays because stringstream will be able to allocate memory optimistically, leading to O(n.log(n)) performance instead of O(n²) for an array of size n for this answer. Also stringstream might not build temporary strings for to_string(i).

                                                          – aberaud
                                                          Feb 17 at 20:10













                                                          1














                                                          I've created an helper header file to add an extended join support.



                                                          Just add the code below to your general header file and include it when needed.



                                                          Usage Examples:



                                                          /* An example for a mapping function. */
                                                          ostream&
                                                          map_numbers(ostream& os, const void* payload, generic_primitive data)
                                                          {
                                                          static string names = {"Zero", "One", "Two", "Three", "Four"};
                                                          os << names[data.as_int];
                                                          const string* post = reinterpret_cast<const string*>(payload);
                                                          if (post) {
                                                          os << " " << *post;
                                                          }
                                                          return os;
                                                          }

                                                          int main() {
                                                          int arr = {0,1,2,3,4};
                                                          vector<int> vec(arr, arr + 5);
                                                          cout << vec << endl; /* Outputs: '0 1 2 3 4' */
                                                          cout << join(vec.begin(), vec.end()) << endl; /* Outputs: '0 1 2 3 4' */
                                                          cout << join(vec.begin(), vec.begin() + 2) << endl; /* Outputs: '0 1 2' */
                                                          cout << join(vec.begin(), vec.end(), ", ") << endl; /* Outputs: '0, 1, 2, 3, 4' */
                                                          cout << join(vec.begin(), vec.end(), ", ", map_numbers) << endl; /* Outputs: 'Zero, One, Two, Three, Four' */
                                                          string post = "Mississippi";
                                                          cout << join(vec.begin() + 1, vec.end(), ", ", map_numbers, &post) << endl; /* Outputs: 'One Mississippi, Two mississippi, Three mississippi, Four mississippi' */
                                                          return 0;
                                                          }


                                                          The code behind the scene:



                                                          #include <iostream>
                                                          #include <vector>
                                                          #include <list>
                                                          #include <set>
                                                          #include <unordered_set>
                                                          using namespace std;

                                                          #define GENERIC_PRIMITIVE_CLASS_BUILDER(T) generic_primitive(const T& v) { value.as_##T = v; }
                                                          #define GENERIC_PRIMITIVE_TYPE_BUILDER(T) T as_##T;

                                                          typedef void* ptr;

                                                          /** A union that could contain a primitive or void*,
                                                          * used for generic function pointers.
                                                          * TODO: add more primitive types as needed.
                                                          */
                                                          struct generic_primitive {
                                                          GENERIC_PRIMITIVE_CLASS_BUILDER(int);
                                                          GENERIC_PRIMITIVE_CLASS_BUILDER(ptr);
                                                          union {
                                                          GENERIC_PRIMITIVE_TYPE_BUILDER(int);
                                                          GENERIC_PRIMITIVE_TYPE_BUILDER(ptr);
                                                          };
                                                          };

                                                          typedef ostream& (*mapping_funct_t)(ostream&, const void*, generic_primitive);
                                                          template<typename T>
                                                          class Join {
                                                          public:
                                                          Join(const T& begin, const T& end,
                                                          const string& separator = " ",
                                                          mapping_funct_t mapping = 0,
                                                          const void* payload = 0):
                                                          m_begin(begin),
                                                          m_end(end),
                                                          m_separator(separator),
                                                          m_mapping(mapping),
                                                          m_payload(payload) {}

                                                          ostream&
                                                          apply(ostream& os) const
                                                          {
                                                          T begin = m_begin;
                                                          T end = m_end;
                                                          if (begin != end)
                                                          if (m_mapping) {
                                                          m_mapping(os, m_payload, *begin++);
                                                          } else {
                                                          os << *begin++;
                                                          }
                                                          while (begin != end) {
                                                          os << m_separator;
                                                          if (m_mapping) {
                                                          m_mapping(os, m_payload, *begin++);
                                                          } else {
                                                          os << *begin++;
                                                          }
                                                          }
                                                          return os;
                                                          }
                                                          private:
                                                          const T& m_begin;
                                                          const T& m_end;
                                                          const string m_separator;
                                                          const mapping_funct_t m_mapping;
                                                          const void* m_payload;
                                                          };

                                                          template <typename T>
                                                          Join<T>
                                                          join(const T& begin, const T& end,
                                                          const string& separator = " ",
                                                          ostream& (*mapping)(ostream&, const void*, generic_primitive) = 0,
                                                          const void* payload = 0)
                                                          {
                                                          return Join<T>(begin, end, separator, mapping, payload);
                                                          }

                                                          template<typename T>
                                                          ostream&
                                                          operator<<(ostream& os, const vector<T>& vec) {
                                                          return join(vec.begin(), vec.end()).apply(os);
                                                          }

                                                          template<typename T>
                                                          ostream&
                                                          operator<<(ostream& os, const list<T>& lst) {
                                                          return join(lst.begin(), lst.end()).apply(os);
                                                          }

                                                          template<typename T>
                                                          ostream&
                                                          operator<<(ostream& os, const set<T>& s) {
                                                          return join(s.begin(), s.end()).apply(os);
                                                          }

                                                          template<typename T>
                                                          ostream&
                                                          operator<<(ostream& os, const Join<T>& vec) {
                                                          return vec.apply(os);
                                                          }





                                                          share|improve this answer






























                                                            1














                                                            I've created an helper header file to add an extended join support.



                                                            Just add the code below to your general header file and include it when needed.



                                                            Usage Examples:



                                                            /* An example for a mapping function. */
                                                            ostream&
                                                            map_numbers(ostream& os, const void* payload, generic_primitive data)
                                                            {
                                                            static string names = {"Zero", "One", "Two", "Three", "Four"};
                                                            os << names[data.as_int];
                                                            const string* post = reinterpret_cast<const string*>(payload);
                                                            if (post) {
                                                            os << " " << *post;
                                                            }
                                                            return os;
                                                            }

                                                            int main() {
                                                            int arr = {0,1,2,3,4};
                                                            vector<int> vec(arr, arr + 5);
                                                            cout << vec << endl; /* Outputs: '0 1 2 3 4' */
                                                            cout << join(vec.begin(), vec.end()) << endl; /* Outputs: '0 1 2 3 4' */
                                                            cout << join(vec.begin(), vec.begin() + 2) << endl; /* Outputs: '0 1 2' */
                                                            cout << join(vec.begin(), vec.end(), ", ") << endl; /* Outputs: '0, 1, 2, 3, 4' */
                                                            cout << join(vec.begin(), vec.end(), ", ", map_numbers) << endl; /* Outputs: 'Zero, One, Two, Three, Four' */
                                                            string post = "Mississippi";
                                                            cout << join(vec.begin() + 1, vec.end(), ", ", map_numbers, &post) << endl; /* Outputs: 'One Mississippi, Two mississippi, Three mississippi, Four mississippi' */
                                                            return 0;
                                                            }


                                                            The code behind the scene:



                                                            #include <iostream>
                                                            #include <vector>
                                                            #include <list>
                                                            #include <set>
                                                            #include <unordered_set>
                                                            using namespace std;

                                                            #define GENERIC_PRIMITIVE_CLASS_BUILDER(T) generic_primitive(const T& v) { value.as_##T = v; }
                                                            #define GENERIC_PRIMITIVE_TYPE_BUILDER(T) T as_##T;

                                                            typedef void* ptr;

                                                            /** A union that could contain a primitive or void*,
                                                            * used for generic function pointers.
                                                            * TODO: add more primitive types as needed.
                                                            */
                                                            struct generic_primitive {
                                                            GENERIC_PRIMITIVE_CLASS_BUILDER(int);
                                                            GENERIC_PRIMITIVE_CLASS_BUILDER(ptr);
                                                            union {
                                                            GENERIC_PRIMITIVE_TYPE_BUILDER(int);
                                                            GENERIC_PRIMITIVE_TYPE_BUILDER(ptr);
                                                            };
                                                            };

                                                            typedef ostream& (*mapping_funct_t)(ostream&, const void*, generic_primitive);
                                                            template<typename T>
                                                            class Join {
                                                            public:
                                                            Join(const T& begin, const T& end,
                                                            const string& separator = " ",
                                                            mapping_funct_t mapping = 0,
                                                            const void* payload = 0):
                                                            m_begin(begin),
                                                            m_end(end),
                                                            m_separator(separator),
                                                            m_mapping(mapping),
                                                            m_payload(payload) {}

                                                            ostream&
                                                            apply(ostream& os) const
                                                            {
                                                            T begin = m_begin;
                                                            T end = m_end;
                                                            if (begin != end)
                                                            if (m_mapping) {
                                                            m_mapping(os, m_payload, *begin++);
                                                            } else {
                                                            os << *begin++;
                                                            }
                                                            while (begin != end) {
                                                            os << m_separator;
                                                            if (m_mapping) {
                                                            m_mapping(os, m_payload, *begin++);
                                                            } else {
                                                            os << *begin++;
                                                            }
                                                            }
                                                            return os;
                                                            }
                                                            private:
                                                            const T& m_begin;
                                                            const T& m_end;
                                                            const string m_separator;
                                                            const mapping_funct_t m_mapping;
                                                            const void* m_payload;
                                                            };

                                                            template <typename T>
                                                            Join<T>
                                                            join(const T& begin, const T& end,
                                                            const string& separator = " ",
                                                            ostream& (*mapping)(ostream&, const void*, generic_primitive) = 0,
                                                            const void* payload = 0)
                                                            {
                                                            return Join<T>(begin, end, separator, mapping, payload);
                                                            }

                                                            template<typename T>
                                                            ostream&
                                                            operator<<(ostream& os, const vector<T>& vec) {
                                                            return join(vec.begin(), vec.end()).apply(os);
                                                            }

                                                            template<typename T>
                                                            ostream&
                                                            operator<<(ostream& os, const list<T>& lst) {
                                                            return join(lst.begin(), lst.end()).apply(os);
                                                            }

                                                            template<typename T>
                                                            ostream&
                                                            operator<<(ostream& os, const set<T>& s) {
                                                            return join(s.begin(), s.end()).apply(os);
                                                            }

                                                            template<typename T>
                                                            ostream&
                                                            operator<<(ostream& os, const Join<T>& vec) {
                                                            return vec.apply(os);
                                                            }





                                                            share|improve this answer




























                                                              1












                                                              1








                                                              1







                                                              I've created an helper header file to add an extended join support.



                                                              Just add the code below to your general header file and include it when needed.



                                                              Usage Examples:



                                                              /* An example for a mapping function. */
                                                              ostream&
                                                              map_numbers(ostream& os, const void* payload, generic_primitive data)
                                                              {
                                                              static string names = {"Zero", "One", "Two", "Three", "Four"};
                                                              os << names[data.as_int];
                                                              const string* post = reinterpret_cast<const string*>(payload);
                                                              if (post) {
                                                              os << " " << *post;
                                                              }
                                                              return os;
                                                              }

                                                              int main() {
                                                              int arr = {0,1,2,3,4};
                                                              vector<int> vec(arr, arr + 5);
                                                              cout << vec << endl; /* Outputs: '0 1 2 3 4' */
                                                              cout << join(vec.begin(), vec.end()) << endl; /* Outputs: '0 1 2 3 4' */
                                                              cout << join(vec.begin(), vec.begin() + 2) << endl; /* Outputs: '0 1 2' */
                                                              cout << join(vec.begin(), vec.end(), ", ") << endl; /* Outputs: '0, 1, 2, 3, 4' */
                                                              cout << join(vec.begin(), vec.end(), ", ", map_numbers) << endl; /* Outputs: 'Zero, One, Two, Three, Four' */
                                                              string post = "Mississippi";
                                                              cout << join(vec.begin() + 1, vec.end(), ", ", map_numbers, &post) << endl; /* Outputs: 'One Mississippi, Two mississippi, Three mississippi, Four mississippi' */
                                                              return 0;
                                                              }


                                                              The code behind the scene:



                                                              #include <iostream>
                                                              #include <vector>
                                                              #include <list>
                                                              #include <set>
                                                              #include <unordered_set>
                                                              using namespace std;

                                                              #define GENERIC_PRIMITIVE_CLASS_BUILDER(T) generic_primitive(const T& v) { value.as_##T = v; }
                                                              #define GENERIC_PRIMITIVE_TYPE_BUILDER(T) T as_##T;

                                                              typedef void* ptr;

                                                              /** A union that could contain a primitive or void*,
                                                              * used for generic function pointers.
                                                              * TODO: add more primitive types as needed.
                                                              */
                                                              struct generic_primitive {
                                                              GENERIC_PRIMITIVE_CLASS_BUILDER(int);
                                                              GENERIC_PRIMITIVE_CLASS_BUILDER(ptr);
                                                              union {
                                                              GENERIC_PRIMITIVE_TYPE_BUILDER(int);
                                                              GENERIC_PRIMITIVE_TYPE_BUILDER(ptr);
                                                              };
                                                              };

                                                              typedef ostream& (*mapping_funct_t)(ostream&, const void*, generic_primitive);
                                                              template<typename T>
                                                              class Join {
                                                              public:
                                                              Join(const T& begin, const T& end,
                                                              const string& separator = " ",
                                                              mapping_funct_t mapping = 0,
                                                              const void* payload = 0):
                                                              m_begin(begin),
                                                              m_end(end),
                                                              m_separator(separator),
                                                              m_mapping(mapping),
                                                              m_payload(payload) {}

                                                              ostream&
                                                              apply(ostream& os) const
                                                              {
                                                              T begin = m_begin;
                                                              T end = m_end;
                                                              if (begin != end)
                                                              if (m_mapping) {
                                                              m_mapping(os, m_payload, *begin++);
                                                              } else {
                                                              os << *begin++;
                                                              }
                                                              while (begin != end) {
                                                              os << m_separator;
                                                              if (m_mapping) {
                                                              m_mapping(os, m_payload, *begin++);
                                                              } else {
                                                              os << *begin++;
                                                              }
                                                              }
                                                              return os;
                                                              }
                                                              private:
                                                              const T& m_begin;
                                                              const T& m_end;
                                                              const string m_separator;
                                                              const mapping_funct_t m_mapping;
                                                              const void* m_payload;
                                                              };

                                                              template <typename T>
                                                              Join<T>
                                                              join(const T& begin, const T& end,
                                                              const string& separator = " ",
                                                              ostream& (*mapping)(ostream&, const void*, generic_primitive) = 0,
                                                              const void* payload = 0)
                                                              {
                                                              return Join<T>(begin, end, separator, mapping, payload);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const vector<T>& vec) {
                                                              return join(vec.begin(), vec.end()).apply(os);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const list<T>& lst) {
                                                              return join(lst.begin(), lst.end()).apply(os);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const set<T>& s) {
                                                              return join(s.begin(), s.end()).apply(os);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const Join<T>& vec) {
                                                              return vec.apply(os);
                                                              }





                                                              share|improve this answer















                                                              I've created an helper header file to add an extended join support.



                                                              Just add the code below to your general header file and include it when needed.



                                                              Usage Examples:



                                                              /* An example for a mapping function. */
                                                              ostream&
                                                              map_numbers(ostream& os, const void* payload, generic_primitive data)
                                                              {
                                                              static string names = {"Zero", "One", "Two", "Three", "Four"};
                                                              os << names[data.as_int];
                                                              const string* post = reinterpret_cast<const string*>(payload);
                                                              if (post) {
                                                              os << " " << *post;
                                                              }
                                                              return os;
                                                              }

                                                              int main() {
                                                              int arr = {0,1,2,3,4};
                                                              vector<int> vec(arr, arr + 5);
                                                              cout << vec << endl; /* Outputs: '0 1 2 3 4' */
                                                              cout << join(vec.begin(), vec.end()) << endl; /* Outputs: '0 1 2 3 4' */
                                                              cout << join(vec.begin(), vec.begin() + 2) << endl; /* Outputs: '0 1 2' */
                                                              cout << join(vec.begin(), vec.end(), ", ") << endl; /* Outputs: '0, 1, 2, 3, 4' */
                                                              cout << join(vec.begin(), vec.end(), ", ", map_numbers) << endl; /* Outputs: 'Zero, One, Two, Three, Four' */
                                                              string post = "Mississippi";
                                                              cout << join(vec.begin() + 1, vec.end(), ", ", map_numbers, &post) << endl; /* Outputs: 'One Mississippi, Two mississippi, Three mississippi, Four mississippi' */
                                                              return 0;
                                                              }


                                                              The code behind the scene:



                                                              #include <iostream>
                                                              #include <vector>
                                                              #include <list>
                                                              #include <set>
                                                              #include <unordered_set>
                                                              using namespace std;

                                                              #define GENERIC_PRIMITIVE_CLASS_BUILDER(T) generic_primitive(const T& v) { value.as_##T = v; }
                                                              #define GENERIC_PRIMITIVE_TYPE_BUILDER(T) T as_##T;

                                                              typedef void* ptr;

                                                              /** A union that could contain a primitive or void*,
                                                              * used for generic function pointers.
                                                              * TODO: add more primitive types as needed.
                                                              */
                                                              struct generic_primitive {
                                                              GENERIC_PRIMITIVE_CLASS_BUILDER(int);
                                                              GENERIC_PRIMITIVE_CLASS_BUILDER(ptr);
                                                              union {
                                                              GENERIC_PRIMITIVE_TYPE_BUILDER(int);
                                                              GENERIC_PRIMITIVE_TYPE_BUILDER(ptr);
                                                              };
                                                              };

                                                              typedef ostream& (*mapping_funct_t)(ostream&, const void*, generic_primitive);
                                                              template<typename T>
                                                              class Join {
                                                              public:
                                                              Join(const T& begin, const T& end,
                                                              const string& separator = " ",
                                                              mapping_funct_t mapping = 0,
                                                              const void* payload = 0):
                                                              m_begin(begin),
                                                              m_end(end),
                                                              m_separator(separator),
                                                              m_mapping(mapping),
                                                              m_payload(payload) {}

                                                              ostream&
                                                              apply(ostream& os) const
                                                              {
                                                              T begin = m_begin;
                                                              T end = m_end;
                                                              if (begin != end)
                                                              if (m_mapping) {
                                                              m_mapping(os, m_payload, *begin++);
                                                              } else {
                                                              os << *begin++;
                                                              }
                                                              while (begin != end) {
                                                              os << m_separator;
                                                              if (m_mapping) {
                                                              m_mapping(os, m_payload, *begin++);
                                                              } else {
                                                              os << *begin++;
                                                              }
                                                              }
                                                              return os;
                                                              }
                                                              private:
                                                              const T& m_begin;
                                                              const T& m_end;
                                                              const string m_separator;
                                                              const mapping_funct_t m_mapping;
                                                              const void* m_payload;
                                                              };

                                                              template <typename T>
                                                              Join<T>
                                                              join(const T& begin, const T& end,
                                                              const string& separator = " ",
                                                              ostream& (*mapping)(ostream&, const void*, generic_primitive) = 0,
                                                              const void* payload = 0)
                                                              {
                                                              return Join<T>(begin, end, separator, mapping, payload);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const vector<T>& vec) {
                                                              return join(vec.begin(), vec.end()).apply(os);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const list<T>& lst) {
                                                              return join(lst.begin(), lst.end()).apply(os);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const set<T>& s) {
                                                              return join(s.begin(), s.end()).apply(os);
                                                              }

                                                              template<typename T>
                                                              ostream&
                                                              operator<<(ostream& os, const Join<T>& vec) {
                                                              return vec.apply(os);
                                                              }






                                                              share|improve this answer














                                                              share|improve this answer



                                                              share|improve this answer








                                                              edited Nov 28 '16 at 19:06

























                                                              answered Nov 28 '16 at 18:54









                                                              Maor GaonMaor Gaon

                                                              112




                                                              112























                                                                  1














                                                                  Here's a generic C++11 solution that will let you do



                                                                  int main() {
                                                                  vector<int> v {1,2,3};
                                                                  cout << join(v, ", ") << endl;
                                                                  string s = join(v, '+').str();
                                                                  }


                                                                  The code is:



                                                                  template<typename Iterable, typename Sep>
                                                                  class Joiner {
                                                                  const Iterable& i_;
                                                                  const Sep& s_;
                                                                  public:
                                                                  Joiner(const Iterable& i, const Sep& s) : i_(i), s_(s) {}
                                                                  std::string str() const {std::stringstream ss; ss << *this; return ss.str();}
                                                                  template<typename I, typename S> friend std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j);
                                                                  };

                                                                  template<typename I, typename S>
                                                                  std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j) {
                                                                  auto elem = j.i_.begin();
                                                                  if (elem != j.i_.end()) {
                                                                  os << *elem;
                                                                  ++elem;
                                                                  while (elem != j.i_.end()) {
                                                                  os << j.s_ << *elem;
                                                                  ++elem;
                                                                  }
                                                                  }
                                                                  return os;
                                                                  }

                                                                  template<typename I, typename S>
                                                                  inline Joiner<I,S> join(const I& i, const S& s) {return Joiner<I,S>(i, s);}





                                                                  share|improve this answer






























                                                                    1














                                                                    Here's a generic C++11 solution that will let you do



                                                                    int main() {
                                                                    vector<int> v {1,2,3};
                                                                    cout << join(v, ", ") << endl;
                                                                    string s = join(v, '+').str();
                                                                    }


                                                                    The code is:



                                                                    template<typename Iterable, typename Sep>
                                                                    class Joiner {
                                                                    const Iterable& i_;
                                                                    const Sep& s_;
                                                                    public:
                                                                    Joiner(const Iterable& i, const Sep& s) : i_(i), s_(s) {}
                                                                    std::string str() const {std::stringstream ss; ss << *this; return ss.str();}
                                                                    template<typename I, typename S> friend std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j);
                                                                    };

                                                                    template<typename I, typename S>
                                                                    std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j) {
                                                                    auto elem = j.i_.begin();
                                                                    if (elem != j.i_.end()) {
                                                                    os << *elem;
                                                                    ++elem;
                                                                    while (elem != j.i_.end()) {
                                                                    os << j.s_ << *elem;
                                                                    ++elem;
                                                                    }
                                                                    }
                                                                    return os;
                                                                    }

                                                                    template<typename I, typename S>
                                                                    inline Joiner<I,S> join(const I& i, const S& s) {return Joiner<I,S>(i, s);}





                                                                    share|improve this answer




























                                                                      1












                                                                      1








                                                                      1







                                                                      Here's a generic C++11 solution that will let you do



                                                                      int main() {
                                                                      vector<int> v {1,2,3};
                                                                      cout << join(v, ", ") << endl;
                                                                      string s = join(v, '+').str();
                                                                      }


                                                                      The code is:



                                                                      template<typename Iterable, typename Sep>
                                                                      class Joiner {
                                                                      const Iterable& i_;
                                                                      const Sep& s_;
                                                                      public:
                                                                      Joiner(const Iterable& i, const Sep& s) : i_(i), s_(s) {}
                                                                      std::string str() const {std::stringstream ss; ss << *this; return ss.str();}
                                                                      template<typename I, typename S> friend std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j);
                                                                      };

                                                                      template<typename I, typename S>
                                                                      std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j) {
                                                                      auto elem = j.i_.begin();
                                                                      if (elem != j.i_.end()) {
                                                                      os << *elem;
                                                                      ++elem;
                                                                      while (elem != j.i_.end()) {
                                                                      os << j.s_ << *elem;
                                                                      ++elem;
                                                                      }
                                                                      }
                                                                      return os;
                                                                      }

                                                                      template<typename I, typename S>
                                                                      inline Joiner<I,S> join(const I& i, const S& s) {return Joiner<I,S>(i, s);}





                                                                      share|improve this answer















                                                                      Here's a generic C++11 solution that will let you do



                                                                      int main() {
                                                                      vector<int> v {1,2,3};
                                                                      cout << join(v, ", ") << endl;
                                                                      string s = join(v, '+').str();
                                                                      }


                                                                      The code is:



                                                                      template<typename Iterable, typename Sep>
                                                                      class Joiner {
                                                                      const Iterable& i_;
                                                                      const Sep& s_;
                                                                      public:
                                                                      Joiner(const Iterable& i, const Sep& s) : i_(i), s_(s) {}
                                                                      std::string str() const {std::stringstream ss; ss << *this; return ss.str();}
                                                                      template<typename I, typename S> friend std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j);
                                                                      };

                                                                      template<typename I, typename S>
                                                                      std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j) {
                                                                      auto elem = j.i_.begin();
                                                                      if (elem != j.i_.end()) {
                                                                      os << *elem;
                                                                      ++elem;
                                                                      while (elem != j.i_.end()) {
                                                                      os << j.s_ << *elem;
                                                                      ++elem;
                                                                      }
                                                                      }
                                                                      return os;
                                                                      }

                                                                      template<typename I, typename S>
                                                                      inline Joiner<I,S> join(const I& i, const S& s) {return Joiner<I,S>(i, s);}






                                                                      share|improve this answer














                                                                      share|improve this answer



                                                                      share|improve this answer








                                                                      edited Apr 11 '17 at 0:26

























                                                                      answered Apr 10 '17 at 0:05









                                                                      n.cailloun.caillou

                                                                      716413




                                                                      716413























                                                                          1














                                                                          The following is a simple and practical way to convert elements in a vector to a string:



                                                                          std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
                                                                          std::ostringstream result;
                                                                          for (const auto number : numbers) {
                                                                          if (result.tellp() > 0) { // not first round
                                                                          result << delimiter;
                                                                          }
                                                                          result << number;
                                                                          }
                                                                          return result.str();
                                                                          }


                                                                          You need to #include <sstream> for ostringstream.






                                                                          share|improve this answer






























                                                                            1














                                                                            The following is a simple and practical way to convert elements in a vector to a string:



                                                                            std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
                                                                            std::ostringstream result;
                                                                            for (const auto number : numbers) {
                                                                            if (result.tellp() > 0) { // not first round
                                                                            result << delimiter;
                                                                            }
                                                                            result << number;
                                                                            }
                                                                            return result.str();
                                                                            }


                                                                            You need to #include <sstream> for ostringstream.






                                                                            share|improve this answer




























                                                                              1












                                                                              1








                                                                              1







                                                                              The following is a simple and practical way to convert elements in a vector to a string:



                                                                              std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
                                                                              std::ostringstream result;
                                                                              for (const auto number : numbers) {
                                                                              if (result.tellp() > 0) { // not first round
                                                                              result << delimiter;
                                                                              }
                                                                              result << number;
                                                                              }
                                                                              return result.str();
                                                                              }


                                                                              You need to #include <sstream> for ostringstream.






                                                                              share|improve this answer















                                                                              The following is a simple and practical way to convert elements in a vector to a string:



                                                                              std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
                                                                              std::ostringstream result;
                                                                              for (const auto number : numbers) {
                                                                              if (result.tellp() > 0) { // not first round
                                                                              result << delimiter;
                                                                              }
                                                                              result << number;
                                                                              }
                                                                              return result.str();
                                                                              }


                                                                              You need to #include <sstream> for ostringstream.







                                                                              share|improve this answer














                                                                              share|improve this answer



                                                                              share|improve this answer








                                                                              edited Jun 16 '18 at 9:31

























                                                                              answered Jun 11 '18 at 21:11









                                                                              mrtsmrts

                                                                              5,10333742




                                                                              5,10333742























                                                                                  0














                                                                                  as @capone did ,



                                                                                  std::string join(const std::vector<std::string> &str_list , 
                                                                                  const std::string &delim=" ")
                                                                                  {
                                                                                  if(str_list.size() == 0) return "" ;
                                                                                  return std::accumulate( str_list.cbegin() + 1,
                                                                                  str_list.cend(),
                                                                                  str_list.at(0) ,
                                                                                  [&delim](const std::string &a , const std::string &b)
                                                                                  {
                                                                                  return a + delim + b ;
                                                                                  } ) ;
                                                                                  }

                                                                                  template <typename ST , typename TT>
                                                                                  std::vector<TT> map(TT (*op)(ST) , const vector<ST> &ori_vec)
                                                                                  {
                                                                                  vector<TT> rst ;
                                                                                  std::transform(ori_vec.cbegin() ,
                                                                                  ori_vec.cend() , back_inserter(rst) ,
                                                                                  [&op](const ST& val){ return op(val) ;} ) ;
                                                                                  return rst ;
                                                                                  }


                                                                                  Then we can call like following :



                                                                                  int main(int argc , char *argv)
                                                                                  {
                                                                                  vector<int> int_vec = {1,2,3,4} ;
                                                                                  vector<string> str_vec = map<int,string>(to_string, int_vec) ;
                                                                                  cout << join(str_vec) << endl ;
                                                                                  return 0 ;
                                                                                  }


                                                                                  just like python :



                                                                                  >>> " ".join( map(str, [1,2,3,4]) )





                                                                                  share|improve this answer




























                                                                                    0














                                                                                    as @capone did ,



                                                                                    std::string join(const std::vector<std::string> &str_list , 
                                                                                    const std::string &delim=" ")
                                                                                    {
                                                                                    if(str_list.size() == 0) return "" ;
                                                                                    return std::accumulate( str_list.cbegin() + 1,
                                                                                    str_list.cend(),
                                                                                    str_list.at(0) ,
                                                                                    [&delim](const std::string &a , const std::string &b)
                                                                                    {
                                                                                    return a + delim + b ;
                                                                                    } ) ;
                                                                                    }

                                                                                    template <typename ST , typename TT>
                                                                                    std::vector<TT> map(TT (*op)(ST) , const vector<ST> &ori_vec)
                                                                                    {
                                                                                    vector<TT> rst ;
                                                                                    std::transform(ori_vec.cbegin() ,
                                                                                    ori_vec.cend() , back_inserter(rst) ,
                                                                                    [&op](const ST& val){ return op(val) ;} ) ;
                                                                                    return rst ;
                                                                                    }


                                                                                    Then we can call like following :



                                                                                    int main(int argc , char *argv)
                                                                                    {
                                                                                    vector<int> int_vec = {1,2,3,4} ;
                                                                                    vector<string> str_vec = map<int,string>(to_string, int_vec) ;
                                                                                    cout << join(str_vec) << endl ;
                                                                                    return 0 ;
                                                                                    }


                                                                                    just like python :



                                                                                    >>> " ".join( map(str, [1,2,3,4]) )





                                                                                    share|improve this answer


























                                                                                      0












                                                                                      0








                                                                                      0







                                                                                      as @capone did ,



                                                                                      std::string join(const std::vector<std::string> &str_list , 
                                                                                      const std::string &delim=" ")
                                                                                      {
                                                                                      if(str_list.size() == 0) return "" ;
                                                                                      return std::accumulate( str_list.cbegin() + 1,
                                                                                      str_list.cend(),
                                                                                      str_list.at(0) ,
                                                                                      [&delim](const std::string &a , const std::string &b)
                                                                                      {
                                                                                      return a + delim + b ;
                                                                                      } ) ;
                                                                                      }

                                                                                      template <typename ST , typename TT>
                                                                                      std::vector<TT> map(TT (*op)(ST) , const vector<ST> &ori_vec)
                                                                                      {
                                                                                      vector<TT> rst ;
                                                                                      std::transform(ori_vec.cbegin() ,
                                                                                      ori_vec.cend() , back_inserter(rst) ,
                                                                                      [&op](const ST& val){ return op(val) ;} ) ;
                                                                                      return rst ;
                                                                                      }


                                                                                      Then we can call like following :



                                                                                      int main(int argc , char *argv)
                                                                                      {
                                                                                      vector<int> int_vec = {1,2,3,4} ;
                                                                                      vector<string> str_vec = map<int,string>(to_string, int_vec) ;
                                                                                      cout << join(str_vec) << endl ;
                                                                                      return 0 ;
                                                                                      }


                                                                                      just like python :



                                                                                      >>> " ".join( map(str, [1,2,3,4]) )





                                                                                      share|improve this answer













                                                                                      as @capone did ,



                                                                                      std::string join(const std::vector<std::string> &str_list , 
                                                                                      const std::string &delim=" ")
                                                                                      {
                                                                                      if(str_list.size() == 0) return "" ;
                                                                                      return std::accumulate( str_list.cbegin() + 1,
                                                                                      str_list.cend(),
                                                                                      str_list.at(0) ,
                                                                                      [&delim](const std::string &a , const std::string &b)
                                                                                      {
                                                                                      return a + delim + b ;
                                                                                      } ) ;
                                                                                      }

                                                                                      template <typename ST , typename TT>
                                                                                      std::vector<TT> map(TT (*op)(ST) , const vector<ST> &ori_vec)
                                                                                      {
                                                                                      vector<TT> rst ;
                                                                                      std::transform(ori_vec.cbegin() ,
                                                                                      ori_vec.cend() , back_inserter(rst) ,
                                                                                      [&op](const ST& val){ return op(val) ;} ) ;
                                                                                      return rst ;
                                                                                      }


                                                                                      Then we can call like following :



                                                                                      int main(int argc , char *argv)
                                                                                      {
                                                                                      vector<int> int_vec = {1,2,3,4} ;
                                                                                      vector<string> str_vec = map<int,string>(to_string, int_vec) ;
                                                                                      cout << join(str_vec) << endl ;
                                                                                      return 0 ;
                                                                                      }


                                                                                      just like python :



                                                                                      >>> " ".join( map(str, [1,2,3,4]) )






                                                                                      share|improve this answer












                                                                                      share|improve this answer



                                                                                      share|improve this answer










                                                                                      answered May 28 '16 at 14:55









                                                                                      小文件小文件

                                                                                      556




                                                                                      556























                                                                                          0














                                                                                          I use something like this



                                                                                          namespace std
                                                                                          {

                                                                                          // for strings join
                                                                                          string to_string( string value )
                                                                                          {
                                                                                          return value;
                                                                                          }

                                                                                          } // namespace std

                                                                                          namespace // anonymous
                                                                                          {

                                                                                          template< typename T >
                                                                                          std::string join( const std::vector<T>& values, char delimiter )
                                                                                          {
                                                                                          std::string result;
                                                                                          for( typename std::vector<T>::size_type idx = 0; idx < values.size(); ++idx )
                                                                                          {
                                                                                          if( idx != 0 )
                                                                                          result += delimiter;
                                                                                          result += std::to_string( values[idx] );
                                                                                          }
                                                                                          return result;
                                                                                          }

                                                                                          } // namespace anonymous





                                                                                          share|improve this answer




























                                                                                            0














                                                                                            I use something like this



                                                                                            namespace std
                                                                                            {

                                                                                            // for strings join
                                                                                            string to_string( string value )
                                                                                            {
                                                                                            return value;
                                                                                            }

                                                                                            } // namespace std

                                                                                            namespace // anonymous
                                                                                            {

                                                                                            template< typename T >
                                                                                            std::string join( const std::vector<T>& values, char delimiter )
                                                                                            {
                                                                                            std::string result;
                                                                                            for( typename std::vector<T>::size_type idx = 0; idx < values.size(); ++idx )
                                                                                            {
                                                                                            if( idx != 0 )
                                                                                            result += delimiter;
                                                                                            result += std::to_string( values[idx] );
                                                                                            }
                                                                                            return result;
                                                                                            }

                                                                                            } // namespace anonymous





                                                                                            share|improve this answer


























                                                                                              0












                                                                                              0








                                                                                              0







                                                                                              I use something like this



                                                                                              namespace std
                                                                                              {

                                                                                              // for strings join
                                                                                              string to_string( string value )
                                                                                              {
                                                                                              return value;
                                                                                              }

                                                                                              } // namespace std

                                                                                              namespace // anonymous
                                                                                              {

                                                                                              template< typename T >
                                                                                              std::string join( const std::vector<T>& values, char delimiter )
                                                                                              {
                                                                                              std::string result;
                                                                                              for( typename std::vector<T>::size_type idx = 0; idx < values.size(); ++idx )
                                                                                              {
                                                                                              if( idx != 0 )
                                                                                              result += delimiter;
                                                                                              result += std::to_string( values[idx] );
                                                                                              }
                                                                                              return result;
                                                                                              }

                                                                                              } // namespace anonymous





                                                                                              share|improve this answer













                                                                                              I use something like this



                                                                                              namespace std
                                                                                              {

                                                                                              // for strings join
                                                                                              string to_string( string value )
                                                                                              {
                                                                                              return value;
                                                                                              }

                                                                                              } // namespace std

                                                                                              namespace // anonymous
                                                                                              {

                                                                                              template< typename T >
                                                                                              std::string join( const std::vector<T>& values, char delimiter )
                                                                                              {
                                                                                              std::string result;
                                                                                              for( typename std::vector<T>::size_type idx = 0; idx < values.size(); ++idx )
                                                                                              {
                                                                                              if( idx != 0 )
                                                                                              result += delimiter;
                                                                                              result += std::to_string( values[idx] );
                                                                                              }
                                                                                              return result;
                                                                                              }

                                                                                              } // namespace anonymous






                                                                                              share|improve this answer












                                                                                              share|improve this answer



                                                                                              share|improve this answer










                                                                                              answered Jun 7 '16 at 6:41









                                                                                              shinshillovshinshillov

                                                                                              114




                                                                                              114























                                                                                                  0














                                                                                                  I started out with @sbi's answer but most of the time ended up piping the resulting string to a stream so created the below solution that can be piped to a stream without the overhead of creating the full string in memory.



                                                                                                  It is used as follows:



                                                                                                  #include "string_join.h"
                                                                                                  #include <iostream>
                                                                                                  #include <vector>

                                                                                                  int main()
                                                                                                  {
                                                                                                  std::vector<int> v = { 1, 2, 3, 4 };
                                                                                                  // String version
                                                                                                  std::string str = join(v, std::string(", "));
                                                                                                  std::cout << str << std::endl;
                                                                                                  // Directly piped to stream version
                                                                                                  std::cout << join(v, std::string(", ")) << std::endl;
                                                                                                  }


                                                                                                  Where string_join.h is:



                                                                                                  #pragma once

                                                                                                  #include <iterator>
                                                                                                  #include <sstream>

                                                                                                  template<typename Str, typename It>
                                                                                                  class joined_strings
                                                                                                  {
                                                                                                  private:
                                                                                                  const It begin, end;
                                                                                                  Str sep;

                                                                                                  public:
                                                                                                  typedef typename Str::value_type char_type;
                                                                                                  typedef typename Str::traits_type traits_type;
                                                                                                  typedef typename Str::allocator_type allocator_type;

                                                                                                  private:
                                                                                                  typedef std::basic_ostringstream<char_type, traits_type, allocator_type>
                                                                                                  ostringstream_type;

                                                                                                  public:
                                                                                                  joined_strings(It begin, const It end, const Str &sep)
                                                                                                  : begin(begin), end(end), sep(sep)
                                                                                                  {
                                                                                                  }

                                                                                                  operator Str() const
                                                                                                  {
                                                                                                  ostringstream_type result;
                                                                                                  result << *this;
                                                                                                  return result.str();
                                                                                                  }

                                                                                                  template<typename ostream_type>
                                                                                                  friend ostream_type& operator<<(
                                                                                                  ostream_type &ostr, const joined_strings<Str, It> &joined)
                                                                                                  {
                                                                                                  It it = joined.begin;
                                                                                                  if(it!=joined.end)
                                                                                                  ostr << *it;
                                                                                                  for(++it; it!=joined.end; ++it)
                                                                                                  ostr << joined.sep << *it;
                                                                                                  return ostr;
                                                                                                  }
                                                                                                  };

                                                                                                  template<typename Str, typename It>
                                                                                                  inline joined_strings<Str, It> join(It begin, const It end, const Str &sep)
                                                                                                  {
                                                                                                  return joined_strings<Str, It>(begin, end, sep);
                                                                                                  }

                                                                                                  template<typename Str, typename Container>
                                                                                                  inline joined_strings<Str, typename Container::const_iterator> join(
                                                                                                  Container container, const Str &sep)
                                                                                                  {
                                                                                                  return join(container.cbegin(), container.cend(), sep);
                                                                                                  }





                                                                                                  share|improve this answer




























                                                                                                    0














                                                                                                    I started out with @sbi's answer but most of the time ended up piping the resulting string to a stream so created the below solution that can be piped to a stream without the overhead of creating the full string in memory.



                                                                                                    It is used as follows:



                                                                                                    #include "string_join.h"
                                                                                                    #include <iostream>
                                                                                                    #include <vector>

                                                                                                    int main()
                                                                                                    {
                                                                                                    std::vector<int> v = { 1, 2, 3, 4 };
                                                                                                    // String version
                                                                                                    std::string str = join(v, std::string(", "));
                                                                                                    std::cout << str << std::endl;
                                                                                                    // Directly piped to stream version
                                                                                                    std::cout << join(v, std::string(", ")) << std::endl;
                                                                                                    }


                                                                                                    Where string_join.h is:



                                                                                                    #pragma once

                                                                                                    #include <iterator>
                                                                                                    #include <sstream>

                                                                                                    template<typename Str, typename It>
                                                                                                    class joined_strings
                                                                                                    {
                                                                                                    private:
                                                                                                    const It begin, end;
                                                                                                    Str sep;

                                                                                                    public:
                                                                                                    typedef typename Str::value_type char_type;
                                                                                                    typedef typename Str::traits_type traits_type;
                                                                                                    typedef typename Str::allocator_type allocator_type;

                                                                                                    private:
                                                                                                    typedef std::basic_ostringstream<char_type, traits_type, allocator_type>
                                                                                                    ostringstream_type;

                                                                                                    public:
                                                                                                    joined_strings(It begin, const It end, const Str &sep)
                                                                                                    : begin(begin), end(end), sep(sep)
                                                                                                    {
                                                                                                    }

                                                                                                    operator Str() const
                                                                                                    {
                                                                                                    ostringstream_type result;
                                                                                                    result << *this;
                                                                                                    return result.str();
                                                                                                    }

                                                                                                    template<typename ostream_type>
                                                                                                    friend ostream_type& operator<<(
                                                                                                    ostream_type &ostr, const joined_strings<Str, It> &joined)
                                                                                                    {
                                                                                                    It it = joined.begin;
                                                                                                    if(it!=joined.end)
                                                                                                    ostr << *it;
                                                                                                    for(++it; it!=joined.end; ++it)
                                                                                                    ostr << joined.sep << *it;
                                                                                                    return ostr;
                                                                                                    }
                                                                                                    };

                                                                                                    template<typename Str, typename It>
                                                                                                    inline joined_strings<Str, It> join(It begin, const It end, const Str &sep)
                                                                                                    {
                                                                                                    return joined_strings<Str, It>(begin, end, sep);
                                                                                                    }

                                                                                                    template<typename Str, typename Container>
                                                                                                    inline joined_strings<Str, typename Container::const_iterator> join(
                                                                                                    Container container, const Str &sep)
                                                                                                    {
                                                                                                    return join(container.cbegin(), container.cend(), sep);
                                                                                                    }





                                                                                                    share|improve this answer


























                                                                                                      0












                                                                                                      0








                                                                                                      0







                                                                                                      I started out with @sbi's answer but most of the time ended up piping the resulting string to a stream so created the below solution that can be piped to a stream without the overhead of creating the full string in memory.



                                                                                                      It is used as follows:



                                                                                                      #include "string_join.h"
                                                                                                      #include <iostream>
                                                                                                      #include <vector>

                                                                                                      int main()
                                                                                                      {
                                                                                                      std::vector<int> v = { 1, 2, 3, 4 };
                                                                                                      // String version
                                                                                                      std::string str = join(v, std::string(", "));
                                                                                                      std::cout << str << std::endl;
                                                                                                      // Directly piped to stream version
                                                                                                      std::cout << join(v, std::string(", ")) << std::endl;
                                                                                                      }


                                                                                                      Where string_join.h is:



                                                                                                      #pragma once

                                                                                                      #include <iterator>
                                                                                                      #include <sstream>

                                                                                                      template<typename Str, typename It>
                                                                                                      class joined_strings
                                                                                                      {
                                                                                                      private:
                                                                                                      const It begin, end;
                                                                                                      Str sep;

                                                                                                      public:
                                                                                                      typedef typename Str::value_type char_type;
                                                                                                      typedef typename Str::traits_type traits_type;
                                                                                                      typedef typename Str::allocator_type allocator_type;

                                                                                                      private:
                                                                                                      typedef std::basic_ostringstream<char_type, traits_type, allocator_type>
                                                                                                      ostringstream_type;

                                                                                                      public:
                                                                                                      joined_strings(It begin, const It end, const Str &sep)
                                                                                                      : begin(begin), end(end), sep(sep)
                                                                                                      {
                                                                                                      }

                                                                                                      operator Str() const
                                                                                                      {
                                                                                                      ostringstream_type result;
                                                                                                      result << *this;
                                                                                                      return result.str();
                                                                                                      }

                                                                                                      template<typename ostream_type>
                                                                                                      friend ostream_type& operator<<(
                                                                                                      ostream_type &ostr, const joined_strings<Str, It> &joined)
                                                                                                      {
                                                                                                      It it = joined.begin;
                                                                                                      if(it!=joined.end)
                                                                                                      ostr << *it;
                                                                                                      for(++it; it!=joined.end; ++it)
                                                                                                      ostr << joined.sep << *it;
                                                                                                      return ostr;
                                                                                                      }
                                                                                                      };

                                                                                                      template<typename Str, typename It>
                                                                                                      inline joined_strings<Str, It> join(It begin, const It end, const Str &sep)
                                                                                                      {
                                                                                                      return joined_strings<Str, It>(begin, end, sep);
                                                                                                      }

                                                                                                      template<typename Str, typename Container>
                                                                                                      inline joined_strings<Str, typename Container::const_iterator> join(
                                                                                                      Container container, const Str &sep)
                                                                                                      {
                                                                                                      return join(container.cbegin(), container.cend(), sep);
                                                                                                      }





                                                                                                      share|improve this answer













                                                                                                      I started out with @sbi's answer but most of the time ended up piping the resulting string to a stream so created the below solution that can be piped to a stream without the overhead of creating the full string in memory.



                                                                                                      It is used as follows:



                                                                                                      #include "string_join.h"
                                                                                                      #include <iostream>
                                                                                                      #include <vector>

                                                                                                      int main()
                                                                                                      {
                                                                                                      std::vector<int> v = { 1, 2, 3, 4 };
                                                                                                      // String version
                                                                                                      std::string str = join(v, std::string(", "));
                                                                                                      std::cout << str << std::endl;
                                                                                                      // Directly piped to stream version
                                                                                                      std::cout << join(v, std::string(", ")) << std::endl;
                                                                                                      }


                                                                                                      Where string_join.h is:



                                                                                                      #pragma once

                                                                                                      #include <iterator>
                                                                                                      #include <sstream>

                                                                                                      template<typename Str, typename It>
                                                                                                      class joined_strings
                                                                                                      {
                                                                                                      private:
                                                                                                      const It begin, end;
                                                                                                      Str sep;

                                                                                                      public:
                                                                                                      typedef typename Str::value_type char_type;
                                                                                                      typedef typename Str::traits_type traits_type;
                                                                                                      typedef typename Str::allocator_type allocator_type;

                                                                                                      private:
                                                                                                      typedef std::basic_ostringstream<char_type, traits_type, allocator_type>
                                                                                                      ostringstream_type;

                                                                                                      public:
                                                                                                      joined_strings(It begin, const It end, const Str &sep)
                                                                                                      : begin(begin), end(end), sep(sep)
                                                                                                      {
                                                                                                      }

                                                                                                      operator Str() const
                                                                                                      {
                                                                                                      ostringstream_type result;
                                                                                                      result << *this;
                                                                                                      return result.str();
                                                                                                      }

                                                                                                      template<typename ostream_type>
                                                                                                      friend ostream_type& operator<<(
                                                                                                      ostream_type &ostr, const joined_strings<Str, It> &joined)
                                                                                                      {
                                                                                                      It it = joined.begin;
                                                                                                      if(it!=joined.end)
                                                                                                      ostr << *it;
                                                                                                      for(++it; it!=joined.end; ++it)
                                                                                                      ostr << joined.sep << *it;
                                                                                                      return ostr;
                                                                                                      }
                                                                                                      };

                                                                                                      template<typename Str, typename It>
                                                                                                      inline joined_strings<Str, It> join(It begin, const It end, const Str &sep)
                                                                                                      {
                                                                                                      return joined_strings<Str, It>(begin, end, sep);
                                                                                                      }

                                                                                                      template<typename Str, typename Container>
                                                                                                      inline joined_strings<Str, typename Container::const_iterator> join(
                                                                                                      Container container, const Str &sep)
                                                                                                      {
                                                                                                      return join(container.cbegin(), container.cend(), sep);
                                                                                                      }






                                                                                                      share|improve this answer












                                                                                                      share|improve this answer



                                                                                                      share|improve this answer










                                                                                                      answered Jan 26 '17 at 11:42









                                                                                                      Nathan PhillipsNathan Phillips

                                                                                                      8,81412217




                                                                                                      8,81412217























                                                                                                          0














                                                                                                          I have wrote the following code. It is based in C# string.join. It works with std::string and std::wstring and many type of vectors. (examples in comments)



                                                                                                          Call it like this:



                                                                                                           std::vector<int> vVectorOfIds = {1, 2, 3, 4, 5};

                                                                                                          std::wstring wstrStringForSQLIn = Join(vVectorOfIds, L',');


                                                                                                          Code:



                                                                                                          // Generic Join template (mimics string.Join() from C#)
                                                                                                          // Written by RandomGuy (stackoverflow) 09-01-2017
                                                                                                          // Based on Brian R. Bondy anwser here:
                                                                                                          // http://stackoverflow.com/questions/1430757/c-vector-to-string
                                                                                                          // Works with char, wchar_t, std::string and std::wstring delimiters
                                                                                                          // Also works with a different types of vectors like ints, floats, longs
                                                                                                          template<typename T, typename D>
                                                                                                          auto Join(const std::vector<T> &vToMerge, const D &delimiter)
                                                                                                          {
                                                                                                          // We use std::conditional to get the correct type for the stringstream (char or wchar_t)
                                                                                                          // stringstream = basic_stringstream<char>, wstringstream = basic_stringstream<wchar_t>
                                                                                                          using strType =
                                                                                                          std::conditional<
                                                                                                          std::is_same<D, std::string>::value,
                                                                                                          char,
                                                                                                          std::conditional<
                                                                                                          std::is_same<D, char>::value,
                                                                                                          char,
                                                                                                          wchar_t
                                                                                                          >::type
                                                                                                          >::type;

                                                                                                          std::basic_stringstream<strType> ss;

                                                                                                          for (size_t i = 0; i < vToMerge.size(); ++i)
                                                                                                          {
                                                                                                          if (i != 0)
                                                                                                          ss << delimiter;
                                                                                                          ss << vToMerge[i];
                                                                                                          }
                                                                                                          return ss.str();
                                                                                                          }





                                                                                                          share|improve this answer






























                                                                                                            0














                                                                                                            I have wrote the following code. It is based in C# string.join. It works with std::string and std::wstring and many type of vectors. (examples in comments)



                                                                                                            Call it like this:



                                                                                                             std::vector<int> vVectorOfIds = {1, 2, 3, 4, 5};

                                                                                                            std::wstring wstrStringForSQLIn = Join(vVectorOfIds, L',');


                                                                                                            Code:



                                                                                                            // Generic Join template (mimics string.Join() from C#)
                                                                                                            // Written by RandomGuy (stackoverflow) 09-01-2017
                                                                                                            // Based on Brian R. Bondy anwser here:
                                                                                                            // http://stackoverflow.com/questions/1430757/c-vector-to-string
                                                                                                            // Works with char, wchar_t, std::string and std::wstring delimiters
                                                                                                            // Also works with a different types of vectors like ints, floats, longs
                                                                                                            template<typename T, typename D>
                                                                                                            auto Join(const std::vector<T> &vToMerge, const D &delimiter)
                                                                                                            {
                                                                                                            // We use std::conditional to get the correct type for the stringstream (char or wchar_t)
                                                                                                            // stringstream = basic_stringstream<char>, wstringstream = basic_stringstream<wchar_t>
                                                                                                            using strType =
                                                                                                            std::conditional<
                                                                                                            std::is_same<D, std::string>::value,
                                                                                                            char,
                                                                                                            std::conditional<
                                                                                                            std::is_same<D, char>::value,
                                                                                                            char,
                                                                                                            wchar_t
                                                                                                            >::type
                                                                                                            >::type;

                                                                                                            std::basic_stringstream<strType> ss;

                                                                                                            for (size_t i = 0; i < vToMerge.size(); ++i)
                                                                                                            {
                                                                                                            if (i != 0)
                                                                                                            ss << delimiter;
                                                                                                            ss << vToMerge[i];
                                                                                                            }
                                                                                                            return ss.str();
                                                                                                            }





                                                                                                            share|improve this answer




























                                                                                                              0












                                                                                                              0








                                                                                                              0







                                                                                                              I have wrote the following code. It is based in C# string.join. It works with std::string and std::wstring and many type of vectors. (examples in comments)



                                                                                                              Call it like this:



                                                                                                               std::vector<int> vVectorOfIds = {1, 2, 3, 4, 5};

                                                                                                              std::wstring wstrStringForSQLIn = Join(vVectorOfIds, L',');


                                                                                                              Code:



                                                                                                              // Generic Join template (mimics string.Join() from C#)
                                                                                                              // Written by RandomGuy (stackoverflow) 09-01-2017
                                                                                                              // Based on Brian R. Bondy anwser here:
                                                                                                              // http://stackoverflow.com/questions/1430757/c-vector-to-string
                                                                                                              // Works with char, wchar_t, std::string and std::wstring delimiters
                                                                                                              // Also works with a different types of vectors like ints, floats, longs
                                                                                                              template<typename T, typename D>
                                                                                                              auto Join(const std::vector<T> &vToMerge, const D &delimiter)
                                                                                                              {
                                                                                                              // We use std::conditional to get the correct type for the stringstream (char or wchar_t)
                                                                                                              // stringstream = basic_stringstream<char>, wstringstream = basic_stringstream<wchar_t>
                                                                                                              using strType =
                                                                                                              std::conditional<
                                                                                                              std::is_same<D, std::string>::value,
                                                                                                              char,
                                                                                                              std::conditional<
                                                                                                              std::is_same<D, char>::value,
                                                                                                              char,
                                                                                                              wchar_t
                                                                                                              >::type
                                                                                                              >::type;

                                                                                                              std::basic_stringstream<strType> ss;

                                                                                                              for (size_t i = 0; i < vToMerge.size(); ++i)
                                                                                                              {
                                                                                                              if (i != 0)
                                                                                                              ss << delimiter;
                                                                                                              ss << vToMerge[i];
                                                                                                              }
                                                                                                              return ss.str();
                                                                                                              }





                                                                                                              share|improve this answer















                                                                                                              I have wrote the following code. It is based in C# string.join. It works with std::string and std::wstring and many type of vectors. (examples in comments)



                                                                                                              Call it like this:



                                                                                                               std::vector<int> vVectorOfIds = {1, 2, 3, 4, 5};

                                                                                                              std::wstring wstrStringForSQLIn = Join(vVectorOfIds, L',');


                                                                                                              Code:



                                                                                                              // Generic Join template (mimics string.Join() from C#)
                                                                                                              // Written by RandomGuy (stackoverflow) 09-01-2017
                                                                                                              // Based on Brian R. Bondy anwser here:
                                                                                                              // http://stackoverflow.com/questions/1430757/c-vector-to-string
                                                                                                              // Works with char, wchar_t, std::string and std::wstring delimiters
                                                                                                              // Also works with a different types of vectors like ints, floats, longs
                                                                                                              template<typename T, typename D>
                                                                                                              auto Join(const std::vector<T> &vToMerge, const D &delimiter)
                                                                                                              {
                                                                                                              // We use std::conditional to get the correct type for the stringstream (char or wchar_t)
                                                                                                              // stringstream = basic_stringstream<char>, wstringstream = basic_stringstream<wchar_t>
                                                                                                              using strType =
                                                                                                              std::conditional<
                                                                                                              std::is_same<D, std::string>::value,
                                                                                                              char,
                                                                                                              std::conditional<
                                                                                                              std::is_same<D, char>::value,
                                                                                                              char,
                                                                                                              wchar_t
                                                                                                              >::type
                                                                                                              >::type;

                                                                                                              std::basic_stringstream<strType> ss;

                                                                                                              for (size_t i = 0; i < vToMerge.size(); ++i)
                                                                                                              {
                                                                                                              if (i != 0)
                                                                                                              ss << delimiter;
                                                                                                              ss << vToMerge[i];
                                                                                                              }
                                                                                                              return ss.str();
                                                                                                              }






                                                                                                              share|improve this answer














                                                                                                              share|improve this answer



                                                                                                              share|improve this answer








                                                                                                              edited Aug 10 '17 at 13:14

























                                                                                                              answered Aug 10 '17 at 11:46









                                                                                                              RandomGuyRandomGuy

                                                                                                              346415




                                                                                                              346415























                                                                                                                  0














                                                                                                                  Expanding on the attempt of @sbi at a generic solution that is not restricted to std::vector<int> or a specific return string type. The code presented below can be used like this:



                                                                                                                  std::vector<int> vec{ 1, 2, 3 };

                                                                                                                  // Call modern range-based overload.
                                                                                                                  auto str = join( vec, "," );
                                                                                                                  auto wideStr = join( vec, L"," );

                                                                                                                  // Call old-school iterator-based overload.
                                                                                                                  auto str = join( vec.begin(), vec.end(), "," );
                                                                                                                  auto wideStr = join( vec.begin(), vec.end(), L"," );


                                                                                                                  In the original code, template argument deduction does not work to produce the right return string type if the separator is a string literal (as in the samples above). In this case, the typedefs like Str::value_type in the function body are incorrect. The code assumes that Str is always a type like std::basic_string, so it obviously fails for string literals.



                                                                                                                  To fix this, the following code tries to deduce only the character type from the separator argument and uses that to produce a default return string type. This is achieved using boost::range_value, which extracts the element type from the given range type.



                                                                                                                  #include <string>
                                                                                                                  #include <sstream>
                                                                                                                  #include <boost/range.hpp>

                                                                                                                  template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
                                                                                                                  Str join( InputIt first, const InputIt last, const Sep& sep )
                                                                                                                  {
                                                                                                                  using char_type = typename Str::value_type;
                                                                                                                  using traits_type = typename Str::traits_type;
                                                                                                                  using allocator_type = typename Str::allocator_type;
                                                                                                                  using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

                                                                                                                  ostringstream_type result;

                                                                                                                  if( first != last )
                                                                                                                  {
                                                                                                                  result << *first++;
                                                                                                                  }
                                                                                                                  while( first != last )
                                                                                                                  {
                                                                                                                  result << sep << *first++;
                                                                                                                  }
                                                                                                                  return result.str();
                                                                                                                  }


                                                                                                                  Now we can easily provide a range-based overload that simply forwards to the iterator-based overload:



                                                                                                                  template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
                                                                                                                  Str join( const InputRange &input, const Sep &sep )
                                                                                                                  {
                                                                                                                  // Include the standard begin() and end() in the overload set for ADL. This makes the
                                                                                                                  // function work for standard types (including arrays), aswell as any custom types
                                                                                                                  // that have begin() and end() member functions or overloads of the standalone functions.
                                                                                                                  using std::begin; using std::end;

                                                                                                                  // Call iterator-based overload.
                                                                                                                  return join( begin(input), end(input), sep );
                                                                                                                  }


                                                                                                                  Live Demo at Coliru






                                                                                                                  share|improve this answer




























                                                                                                                    0














                                                                                                                    Expanding on the attempt of @sbi at a generic solution that is not restricted to std::vector<int> or a specific return string type. The code presented below can be used like this:



                                                                                                                    std::vector<int> vec{ 1, 2, 3 };

                                                                                                                    // Call modern range-based overload.
                                                                                                                    auto str = join( vec, "," );
                                                                                                                    auto wideStr = join( vec, L"," );

                                                                                                                    // Call old-school iterator-based overload.
                                                                                                                    auto str = join( vec.begin(), vec.end(), "," );
                                                                                                                    auto wideStr = join( vec.begin(), vec.end(), L"," );


                                                                                                                    In the original code, template argument deduction does not work to produce the right return string type if the separator is a string literal (as in the samples above). In this case, the typedefs like Str::value_type in the function body are incorrect. The code assumes that Str is always a type like std::basic_string, so it obviously fails for string literals.



                                                                                                                    To fix this, the following code tries to deduce only the character type from the separator argument and uses that to produce a default return string type. This is achieved using boost::range_value, which extracts the element type from the given range type.



                                                                                                                    #include <string>
                                                                                                                    #include <sstream>
                                                                                                                    #include <boost/range.hpp>

                                                                                                                    template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
                                                                                                                    Str join( InputIt first, const InputIt last, const Sep& sep )
                                                                                                                    {
                                                                                                                    using char_type = typename Str::value_type;
                                                                                                                    using traits_type = typename Str::traits_type;
                                                                                                                    using allocator_type = typename Str::allocator_type;
                                                                                                                    using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

                                                                                                                    ostringstream_type result;

                                                                                                                    if( first != last )
                                                                                                                    {
                                                                                                                    result << *first++;
                                                                                                                    }
                                                                                                                    while( first != last )
                                                                                                                    {
                                                                                                                    result << sep << *first++;
                                                                                                                    }
                                                                                                                    return result.str();
                                                                                                                    }


                                                                                                                    Now we can easily provide a range-based overload that simply forwards to the iterator-based overload:



                                                                                                                    template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
                                                                                                                    Str join( const InputRange &input, const Sep &sep )
                                                                                                                    {
                                                                                                                    // Include the standard begin() and end() in the overload set for ADL. This makes the
                                                                                                                    // function work for standard types (including arrays), aswell as any custom types
                                                                                                                    // that have begin() and end() member functions or overloads of the standalone functions.
                                                                                                                    using std::begin; using std::end;

                                                                                                                    // Call iterator-based overload.
                                                                                                                    return join( begin(input), end(input), sep );
                                                                                                                    }


                                                                                                                    Live Demo at Coliru






                                                                                                                    share|improve this answer


























                                                                                                                      0












                                                                                                                      0








                                                                                                                      0







                                                                                                                      Expanding on the attempt of @sbi at a generic solution that is not restricted to std::vector<int> or a specific return string type. The code presented below can be used like this:



                                                                                                                      std::vector<int> vec{ 1, 2, 3 };

                                                                                                                      // Call modern range-based overload.
                                                                                                                      auto str = join( vec, "," );
                                                                                                                      auto wideStr = join( vec, L"," );

                                                                                                                      // Call old-school iterator-based overload.
                                                                                                                      auto str = join( vec.begin(), vec.end(), "," );
                                                                                                                      auto wideStr = join( vec.begin(), vec.end(), L"," );


                                                                                                                      In the original code, template argument deduction does not work to produce the right return string type if the separator is a string literal (as in the samples above). In this case, the typedefs like Str::value_type in the function body are incorrect. The code assumes that Str is always a type like std::basic_string, so it obviously fails for string literals.



                                                                                                                      To fix this, the following code tries to deduce only the character type from the separator argument and uses that to produce a default return string type. This is achieved using boost::range_value, which extracts the element type from the given range type.



                                                                                                                      #include <string>
                                                                                                                      #include <sstream>
                                                                                                                      #include <boost/range.hpp>

                                                                                                                      template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
                                                                                                                      Str join( InputIt first, const InputIt last, const Sep& sep )
                                                                                                                      {
                                                                                                                      using char_type = typename Str::value_type;
                                                                                                                      using traits_type = typename Str::traits_type;
                                                                                                                      using allocator_type = typename Str::allocator_type;
                                                                                                                      using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

                                                                                                                      ostringstream_type result;

                                                                                                                      if( first != last )
                                                                                                                      {
                                                                                                                      result << *first++;
                                                                                                                      }
                                                                                                                      while( first != last )
                                                                                                                      {
                                                                                                                      result << sep << *first++;
                                                                                                                      }
                                                                                                                      return result.str();
                                                                                                                      }


                                                                                                                      Now we can easily provide a range-based overload that simply forwards to the iterator-based overload:



                                                                                                                      template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
                                                                                                                      Str join( const InputRange &input, const Sep &sep )
                                                                                                                      {
                                                                                                                      // Include the standard begin() and end() in the overload set for ADL. This makes the
                                                                                                                      // function work for standard types (including arrays), aswell as any custom types
                                                                                                                      // that have begin() and end() member functions or overloads of the standalone functions.
                                                                                                                      using std::begin; using std::end;

                                                                                                                      // Call iterator-based overload.
                                                                                                                      return join( begin(input), end(input), sep );
                                                                                                                      }


                                                                                                                      Live Demo at Coliru






                                                                                                                      share|improve this answer













                                                                                                                      Expanding on the attempt of @sbi at a generic solution that is not restricted to std::vector<int> or a specific return string type. The code presented below can be used like this:



                                                                                                                      std::vector<int> vec{ 1, 2, 3 };

                                                                                                                      // Call modern range-based overload.
                                                                                                                      auto str = join( vec, "," );
                                                                                                                      auto wideStr = join( vec, L"," );

                                                                                                                      // Call old-school iterator-based overload.
                                                                                                                      auto str = join( vec.begin(), vec.end(), "," );
                                                                                                                      auto wideStr = join( vec.begin(), vec.end(), L"," );


                                                                                                                      In the original code, template argument deduction does not work to produce the right return string type if the separator is a string literal (as in the samples above). In this case, the typedefs like Str::value_type in the function body are incorrect. The code assumes that Str is always a type like std::basic_string, so it obviously fails for string literals.



                                                                                                                      To fix this, the following code tries to deduce only the character type from the separator argument and uses that to produce a default return string type. This is achieved using boost::range_value, which extracts the element type from the given range type.



                                                                                                                      #include <string>
                                                                                                                      #include <sstream>
                                                                                                                      #include <boost/range.hpp>

                                                                                                                      template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
                                                                                                                      Str join( InputIt first, const InputIt last, const Sep& sep )
                                                                                                                      {
                                                                                                                      using char_type = typename Str::value_type;
                                                                                                                      using traits_type = typename Str::traits_type;
                                                                                                                      using allocator_type = typename Str::allocator_type;
                                                                                                                      using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

                                                                                                                      ostringstream_type result;

                                                                                                                      if( first != last )
                                                                                                                      {
                                                                                                                      result << *first++;
                                                                                                                      }
                                                                                                                      while( first != last )
                                                                                                                      {
                                                                                                                      result << sep << *first++;
                                                                                                                      }
                                                                                                                      return result.str();
                                                                                                                      }


                                                                                                                      Now we can easily provide a range-based overload that simply forwards to the iterator-based overload:



                                                                                                                      template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
                                                                                                                      Str join( const InputRange &input, const Sep &sep )
                                                                                                                      {
                                                                                                                      // Include the standard begin() and end() in the overload set for ADL. This makes the
                                                                                                                      // function work for standard types (including arrays), aswell as any custom types
                                                                                                                      // that have begin() and end() member functions or overloads of the standalone functions.
                                                                                                                      using std::begin; using std::end;

                                                                                                                      // Call iterator-based overload.
                                                                                                                      return join( begin(input), end(input), sep );
                                                                                                                      }


                                                                                                                      Live Demo at Coliru







                                                                                                                      share|improve this answer












                                                                                                                      share|improve this answer



                                                                                                                      share|improve this answer










                                                                                                                      answered Sep 26 '18 at 19:49









                                                                                                                      zett42zett42

                                                                                                                      7,6733841




                                                                                                                      7,6733841






























                                                                                                                          draft saved

                                                                                                                          draft discarded




















































                                                                                                                          Thanks for contributing an answer to Stack Overflow!


                                                                                                                          • Please be sure to answer the question. Provide details and share your research!

                                                                                                                          But avoid



                                                                                                                          • Asking for help, clarification, or responding to other answers.

                                                                                                                          • Making statements based on opinion; back them up with references or personal experience.


                                                                                                                          To learn more, see our tips on writing great answers.




                                                                                                                          draft saved


                                                                                                                          draft discarded














                                                                                                                          StackExchange.ready(
                                                                                                                          function () {
                                                                                                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1430757%2fconvert-a-vectorint-to-a-string%23new-answer', 'question_page');
                                                                                                                          }
                                                                                                                          );

                                                                                                                          Post as a guest















                                                                                                                          Required, but never shown





















































                                                                                                                          Required, but never shown














                                                                                                                          Required, but never shown












                                                                                                                          Required, but never shown







                                                                                                                          Required, but never shown

































                                                                                                                          Required, but never shown














                                                                                                                          Required, but never shown












                                                                                                                          Required, but never shown







                                                                                                                          Required, but never shown







                                                                                                                          這個網誌中的熱門文章

                                                                                                                          Xamarin.form Move up view when keyboard appear

                                                                                                                          Post-Redirect-Get with Spring WebFlux and Thymeleaf

                                                                                                                          Anylogic : not able to use stopDelay()