C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

something like Perl's join function

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Irek Szczesniak
Guest





PostPosted: Thu May 11, 2006 10:21 pm    Post subject: something like Perl's join function Reply with quote



I like the Perl's join function and want to get something similar in
C++, preferably with std or boost. In Perl you can say:

print join(", ", (10, 2, 15));

which prints "10, 2, 15".

In C++ you can get a similar thing this way:

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

using namespace std;

int main()
{
int table[] = {10, 2, 15};
copy(table, table + 3, ostream_iterator<int>(cout, ", "));
}

However, you get "10, 2, 15, ", i.e. you get a trailing unwanted ", ".

Do you know some nifty way of getting the functionality of the Perl's
join function?


Thanks & best,
Irek

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carlos Moreno
Guest





PostPosted: Sat May 13, 2006 12:21 am    Post subject: Re: something like Perl's join function Reply with quote



Irek Szczesniak wrote:
Quote:
I like the Perl's join function and want to get something similar in
C++, preferably with std or boost. In Perl you can say:

print join(", ", (10, 2, 15));

which prints "10, 2, 15".

In C++ you can get a similar thing this way:

#include <iostream
#include <iterator
#include <algorithm

using namespace std;

int main()
{
int table[] = {10, 2, 15};
copy(table, table + 3, ostream_iterator<int>(cout, ", "));
}

However, you get "10, 2, 15, ", i.e. you get a trailing unwanted ", ".

Do you know some nifty way of getting the functionality of the Perl's
join function?

I don't think any "out of the box" solution is available.

I believe I've written at some point a join function (creating
SQL statements where I needed an IN operation in the WHERE
clause).

It's not too bad:

// untested, off the top of my head code

template <typename Iterator>
string join (Iterator begin, Iterator end, const string & sep)
{
typedef typename iterator_traits<Iterator>::value_type Value;

if (begin == end) return "";

--end;
ostringstream joined;
copy (begin, end, ostream_iterator<Value>(joined, sep));
joined << *end;

return joined.str();
}

If you want to avoid the trouble with the iterator_traits, you
might use your hand-coded loop using << instead of copy for the
entire sequence. You could also overload it to receive a
container (and then inside the function you take cont.begin()
and cont.end())

HTH,

Carlos
--

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Seungbeom Kim
Guest





PostPosted: Mon May 15, 2006 12:22 am    Post subject: Re: something like Perl's join function Reply with quote



Irek Szczesniak wrote:
Quote:
I like the Perl's join function and want to get something similar in
C++, preferably with std or boost. In Perl you can say:

print join(", ", (10, 2, 15));

which prints "10, 2, 15".

In C++ you can get a similar thing this way:

#include <iostream
#include <iterator
#include <algorithm

using namespace std;

int main()
{
int table[] = {10, 2, 15};
copy(table, table + 3, ostream_iterator<int>(cout, ", "));
}

However, you get "10, 2, 15, ", i.e. you get a trailing unwanted ", ".

Do you know some nifty way of getting the functionality of the Perl's
join function?

A quick implementation of mine:

#include <ostream>
#include <iterator>

template <typename T, typename CharT = char,
typename Traits = std::char_traits<CharT> >
class ostream_join_iterator
: public std::iterator<std::output_iterator_tag, void, void, void, void>
{
public:
typedef CharT char_type;
typedef Traits traits_type;
typedef std::basic_ostream<CharT, Traits> ostream_type;

ostream_join_iterator(ostream_type& s, const char_type* c = 0)
: stream(&s), string(c), print_string(0) { }

ostream_join_iterator& operator=(const T& value)
{
if (print_string) *stream << print_string;
print_string = string;
*stream << value;
return *this;
}

ostream_join_iterator& operator*() { return *this; }
ostream_join_iterator& operator++() { return *this; }
ostream_join_iterator& operator++(int) { return *this; }

private:
ostream_type* stream;
const char_type* string;
const char_type* print_string;
};

Use this as a replacement of std::ostream_iterator:
std::copy(begin, end, ostream_join_iterator<int>(std::cout, ", "));

--
Seungbeom Kim

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Joshua Lehrer
Guest





PostPosted: Mon May 15, 2006 12:21 pm    Post subject: Re: something like Perl's join function Reply with quote

Irek Szczesniak wrote:
Quote:
I like the Perl's join function and want to get something similar in
C++, preferably with std or boost. In Perl you can say:

print join(", ", (10, 2, 15));


I have a solution that lets you do:

std::cout << join(begin,end,sep) << std::endl;
and
join(begin,end,sep).toString();

Unfortunately, I can not paste the code here. However, here is the
approach:

First, you need a templated creator function, called join, that returns
an object, JoinObj. JoinObj stores the iterators and the separator.
This function is a lot like make_pair.

JoinObj then has the ability to insert itself into an ostream and also
has the method toString() on it. You can add an operator string() if
you like, as well.

The entire thing is just a few lines of code.

Enjoy,

joshua lehrer
http://www.lehrerfamily.com/


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
abdallaalothman@myway.com
Guest





PostPosted: Mon May 15, 2006 12:21 pm    Post subject: Re: something like Perl's join function Reply with quote

Irek Szczesniak wrote:
[...]
Quote:
Do you know some nifty way of getting the functionality of the Perl's
join function?

I wanted something like the QStringList::join() to be in a custom
string class. Here's what I have (works with deques and vectors):

template<template<typename A> class X, typename T>
T join(const X<T> &c, const T &s)
{
T temp;

for(typename X<T>::const_iterator i = c.begin(); i != c.end(); ++i)
{
temp += *i;
if( i != c.end() -1 )
{
temp += s;
}
}
return temp;
}

int main()
{
vector<string> sv;
sv.push_back("he");
sv.push_back("him");
sv.push_back("she");
sv.push_back("shim");
string s = join(sv, string(" | "));
cout << s << endl;
return 0;
}

You can use stringstreams to convert to and from different types.

Abdalla Alothman


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carl Barron
Guest





PostPosted: Mon May 15, 2006 7:21 pm    Post subject: Re: something like Perl's join function Reply with quote

In article <1147678546.453775.221810 (AT) u72g2000cwu (DOT) googlegroups.com>,
<"abdallaalothman (AT) myway (DOT) com"> wrote:

Quote:
Irek Szczesniak wrote:
[...]
Do you know some nifty way of getting the functionality of the Perl's
join function?

I wanted something like the QStringList::join() to be in a custom
string class. Here's what I have (works with deques and vectors):

template<template<typename A> class X, typename T
T join(const X<T> &c, const T &s)
{
T temp;

for(typename X<T>::const_iterator i = c.begin(); i != c.end(); ++i)
{
temp += *i;
if( i != c.end() -1 )
{
temp += s;
}
}
return temp;
}

int main()
{
vector<string> sv;
sv.push_back("he");
sv.push_back("him");
sv.push_back("she");
sv.push_back("shim");
string s = join(sv, string(" | "));
cout << s << endl;
return 0;
}

You can use stringstreams to convert to and from different types.

That won't compile:) std::vector has two template paramenters not

one:) default template parameters do not reduce the # of template
paramenters of the type only provide a short hand to use a specific one
without specifying it. This is one reason why the option of
implementors to add extra default args was removed from the standard.

if you use something like
template <class C,class T>
T join(const C &c,const T &i)
{
for(typename C::const_iterator i= // etc.
}
it will compile, If you want to force the value type of the container
to be T as well [the above only requires it be convertable to T.]
use something like

template <class C,class T>
T join (const C &c,const T &d, boost::enable_if
<
boost::is_same
<
typename C::value_type,
T
Quote:

::type *=0)
{

// etc.
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Abdalla Alothman
Guest





PostPosted: Tue May 16, 2006 10:21 am    Post subject: Re: something like Perl's join function Reply with quote

Carl Barron wrote:
Quote:

That won't compile:)

It compiles fine under gcc 3.3.5 if the container is a vector or a
deque.
If there's a need to use vectors, deques, lists, and sets, I would
change
that line:

if( i != c.end() -1 )

to:

if( distance(i, c.end()) != 1 )

I haven't tested it on any other compiler than g++ (3.3.5), to be
honest.
So perhaps it might not compile on other implementations.

Thanks for the tip, though. :)

Abdalla Alothman


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carl Barron
Guest





PostPosted: Wed May 17, 2006 2:21 am    Post subject: Re: something like Perl's join function Reply with quote

In article <1147724011.621368.311160 (AT) y43g2000cwc (DOT) googlegroups.com>,
Abdalla Alothman <abdalla_ (AT) myway (DOT) com> wrote:

Quote:
Carl Barron wrote:

That won't compile:)

Metrowerks 9.6 does not compile your code! If the allocator argument

is added then it will work for sequence containers but no as written.

Quote:
It compiles fine under gcc 3.3.5 if the container is a vector or a
deque.
either your code and post are differenet or there is a bug in gcc

3.3.5. It is non standard if it passes through...

Quote:
If there's a need to use vectors, deques, lists, and sets, I would
change
that line:

Sorry there is no type std::vector<T> only std::vector<T,A> where

ussually defaults to std::allocator<T>.

template <class T,class A=std::allocator<T> >
class vector { /**/};

see 14.1 for details...

just like void f(int i= 0) { /* */}

f() is not function call with no args but a function call with one arg
that is 0.

void (*p)() = f; // syntax error.
void (*p)(int) = f;// ok.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Fri May 19, 2006 10:21 am    Post subject: Re: something like Perl's join function Reply with quote

Carlos, Seungbeom, Abdalla, Carl, Joshua and others,

Thanks for your replies. Seungbeom, your ostream_join_iterator is
really cool. I wish it got to the standard some day, but I can only
wish. Smile Finally I have this minimalistic << operator for a vector
(shown below) and now it's sufficient for me.


Best,
Irek

*******************************************

#include <iostream>
#include <vector>

using namespace std;

template <typename T>
ostream &operator << (ostream &os, const vector<T> &v)
{
typename vector<T>::const_iterator i = v.begin();

while(i != v.end())
{
os << *i;
if (++i != v.end())
os << ", ";
}

return os;
}

int main()
{
vector<int> a;

cout << a << endl;
a.push_back(1);
cout << a << endl;
a.push_back(2);
cout << a << endl;
a.push_back(3);
cout << a << endl;

return 0;
}


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Abdalla Alothman
Guest





PostPosted: Tue May 23, 2006 11:21 am    Post subject: Re: something like Perl's join function Reply with quote

Greetings, Carl.

Carl Barron wrote:

Quote:
Metrowerks 9.6 does not compile your code! If the allocator argument
is added then it will work for sequence containers but no as written.

I see. I'm afraid I can't help (I don't have time).

If you apply the change in the second message and use class X, 'join'
will work with sets, which are not sequential.

template<class X, typename T>
T join(const X &c, const T &s)
{
T temp;

for(typename X::const_iterator i = c.begin(); i != c.end(); ++i)
{
temp += *i;
if( distance(i, c.end()) != 1 )
temp += s;
}
return temp;
}

Try it out with lists, vectors, deques, and sets and try compiling it
here (if your compiler still complains):

http://www.comeaucomputing.com/tryitout/

Quote:
either your code and post are differenet or there is a bug in gcc
3.3.5. It is non standard if it passes through...

It's not a "bug," probably just a difference between STL
implementations and how the compiler orders and processes templates. I
know of two (I think there are around four) different implementations
and they are not one and the same.

Quote:
template <class T,class A=std::allocator<T
class vector { /**/};

I'm aware of that.

vector, in gcc, is implemented as such (SGI), but it inherits (by
protected means) from a base class. The code is available online, I
would rather check it before making conclusions. I don't think the
problem is in vector's implementation, but probably the order in
processing the template.

Your analogy of function pointers does not quite apply because
templates and function pointers are treated differently by compilers.

Sincerely,
Abdalla Alothman


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carl Barron
Guest





PostPosted: Tue May 23, 2006 10:21 pm    Post subject: Re: something like Perl's join function Reply with quote

In article <1148182179.893052.40720 (AT) 38g2000cwa (DOT) googlegroups.com>,
Abdalla Alothman <abdalla_ (AT) myway (DOT) com> wrote:

Quote:
Greetings, Carl.

Carl Barron wrote:

Metrowerks 9.6 does not compile your code! If the allocator argument
is added then it will work for sequence containers but no as written.

I see. I'm afraid I can't help (I don't have time).

If you apply the change in the second message and use class X, 'join'
will work with sets, which are not sequential.

template<class X, typename T
T join(const X &c, const T &s)
{
T temp;

for(typename X::const_iterator i = c.begin(); i != c.end(); ++i)
{
temp += *i;
if( distance(i, c.end()) != 1 )
temp += s;
}
return temp;
}

This is not the original code:) as above is fine as long as T is

convertable to X::value_type, which it probably is any reasonable use
of this function template.

note this could be improved on by using another typename ,
X::const_iterator jt(i);
if(++jt !=c.end()) temp += s;
is more effiicient than if(distance(i,c.end()) !=1 ) temp+=s;
as c.size() gets larger.

Default arguments do not provid new signatures, only a value to use
if it is not explicitly provided. That makes the original code
invalid.
This is one reason mpl uses place holders and does not use template
template parameters....

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.