|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
I've just written the below as an exercise (don't worry about the lack
of checking), but I was wondering why I needed to write a struct with an operator() as a parameter to supply to the STL transform() function? #include <algorithm> #include <iostream> #include <fstream> #include <iterator> #include <vector> #include <string> #include <cctype> using namespace std; struct lowercase { string operator()(const string& s) { string lower(s); for (size_t i = 0; i < s.length(); ++i) lower[i] = tolower(lower[i]); return lower; } }; int main(int argc, char* argv[]) { if (argc > 1) { ifstream in(argv[1]); vector<string> vs; copy(istream_iterator<string>(in), istream_iterator<string>(), back_inserter(vs)); transform(vs.begin(), vs.end(), vs.begin(), lowercase()); sort(vs.begin(), vs.end()); vector<string>::iterator it = unique(vs.begin(), vs.end ()); vs.resize(it - vs.begin()); copy(vs.begin(), vs.end(), ostream_iterator<string> (cout, "\n")); } } -- http://www.munted.org.uk Fearsome grindings. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Alex Buell wrote:
> I've just written the below as an exercise (don't worry about the lack > of checking), but I was wondering why I needed to write a struct with > an operator() as a parameter to supply to the STL transform() function? You don't. > #include <algorithm> > #include <iostream> > #include <fstream> > #include <iterator> > #include <vector> > #include <string> > #include <cctype> > > using namespace std; > > struct lowercase > { > string operator()(const string& s) > { > string lower(s); > > for (size_t i = 0; i < s.length(); ++i) > lower[i] = tolower(lower[i]); > > return lower; > } > }; > > int main(int argc, char* argv[]) > { > if (argc > 1) > { > ifstream in(argv[1]); > vector<string> vs; > > copy(istream_iterator<string>(in), > istream_iterator<string>(), back_inserter(vs)); transform(vs.begin(), > vs.end(), vs.begin(), lowercase()); sort(vs.begin(), vs.end()); > > vector<string>::iterator it = unique(vs.begin(), vs.end > ()); vs.resize(it - vs.begin()); > > copy(vs.begin(), vs.end(), ostream_iterator<string> > (cout, "\n")); } > } Consider: #include <algorithm> #include <iostream> #include <fstream> #include <iterator> #include <vector> #include <string> #include <cctype> using namespace std; string lowercase ( string const s ) { string lower(s); for (size_t i = 0; i < s.length(); ++i) { lower[i] = tolower(lower[i]); } return lower; } int main(int argc, char* argv[]) { if (argc > 1) { ifstream in(argv[1]); vector<string> vs; copy(istream_iterator<string>(in), istream_iterator<string>(), back_inserter(vs)); transform(vs.begin(), vs.end(), vs.begin(), &lowercase); sort(vs.begin(), vs.end()); vector<string>::iterator it = unique(vs.begin(), vs.end()); vs.resize(it - vs.begin()); copy(vs.begin(), vs.end(), ostream_iterator<string>(cout, "\n")); } } Now, which way is better in which ways is a different matter. Best Kai-Uwe Bux |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
Alex Buell wrote:
> I've just written the below as an exercise (don't worry about the lack > of checking), but I was wondering why I needed to write a struct with > an operator() as a parameter to supply to the STL transform() > function? You didn't. You could just write it as a stand-alone function. Less typing, and you wouldn't need the () after it when calling 'transform'. Tty it string lowercase(const string& s) { ... // your implementation } .... transform(vs.begin(), vs.end(), vs.begin(), lowercase); > > #include <algorithm> > #include <iostream> > #include <fstream> > #include <iterator> > #include <vector> > #include <string> > #include <cctype> > > using namespace std; > > struct lowercase > { > string operator()(const string& s) > { > string lower(s); > > for (size_t i = 0; i < s.length(); ++i) > lower[i] = tolower(lower[i]); > > return lower; > } > }; > > int main(int argc, char* argv[]) > { > if (argc > 1) > { > ifstream in(argv[1]); > vector<string> vs; > > copy(istream_iterator<string>(in), > istream_iterator<string>(), back_inserter(vs)); transform(vs.begin(), > vs.end(), vs.begin(), lowercase()); sort(vs.begin(), vs.end()); > > vector<string>::iterator it = unique(vs.begin(), vs.end > ()); vs.resize(it - vs.begin()); > > copy(vs.begin(), vs.end(), ostream_iterator<string> > (cout, "\n")); } > } V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
On Mon, 10 Dec 2007 20:28:37 -0500, I waved a wand and this message
magically appears in front of Kai-Uwe Bux: > string lowercase ( string const s ) { > string lower(s); > for (size_t i = 0; i < s.length(); ++i) { > lower[i] = tolower(lower[i]); > } > return lower; > } Thanks, I did just that when writing the exercise, but the compiler wouldn't accept it - I know why now - it doesn't need the () when calling a function. For operator () functions, it does need the (). Thanks for pointing out the differences! Thanks also to Bazarov! Regards, Alex -- http://www.munted.org.uk Fearsome grindings. |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
On Dec 11, 2:28 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Alex Buell wrote: > > I've just written the below as an exercise (don't worry about the lack > > of checking), but I was wondering why I needed to write a struct with > > an operator() as a parameter to supply to the STL transform() function? > > You don't. > > > > > #include <algorithm> > > #include <iostream> > > #include <fstream> > > #include <iterator> > > #include <vector> > > #include <string> > > #include <cctype> > > > using namespace std; > > > struct lowercase > > { > > string operator()(const string& s) > > { > > string lower(s); > > > for (size_t i = 0; i < s.length(); ++i) > > lower[i] = tolower(lower[i]); > > > return lower; > > } > > }; > > > int main(int argc, char* argv[]) > > { > > if (argc > 1) > > { > > ifstream in(argv[1]); > > vector<string> vs; > > > copy(istream_iterator<string>(in), > > istream_iterator<string>(), back_inserter(vs)); transform(vs.begin(), > > vs.end(), vs.begin(), lowercase()); sort(vs.begin(), vs.end()); > > > vector<string>::iterator it = unique(vs.begin(), vs.end > > ()); vs.resize(it - vs.begin()); > > > copy(vs.begin(), vs.end(), ostream_iterator<string> > > (cout, "\n")); } > > } > > Consider: > > #include <algorithm> > #include <iostream> > #include <fstream> > #include <iterator> > #include <vector> > #include <string> > #include <cctype> > > using namespace std; > > string lowercase ( string const s ) { > string lower(s); > for (size_t i = 0; i < s.length(); ++i) { > lower[i] = tolower(lower[i]); > } > return lower; > > } > > int main(int argc, char* argv[]) { > if (argc > 1) { > ifstream in(argv[1]); > vector<string> vs; > > copy(istream_iterator<string>(in), > istream_iterator<string>(), > back_inserter(vs)); > transform(vs.begin(), vs.end(), vs.begin(), &lowercase); > sort(vs.begin(), vs.end()); > > vector<string>::iterator it = > unique(vs.begin(), vs.end()); > vs.resize(it - vs.begin()); > > copy(vs.begin(), vs.end(), > ostream_iterator<string>(cout, "\n")); } > > } > > Now, which way is better in which ways is a different matter. Is there actually any difference at all (if we except the passing by copy in your implementation) ? Thanks -Mathieu |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
On Dec 11, 10:37 am, mathieu <mathieu.malate...@gmail.com> wrote:
> On Dec 11, 2:28 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote: > > Alex Buell wrote: > > > I've just written the below as an exercise (don't worry about the lack > > > of checking), but I was wondering why I needed to write a struct with > > > an operator() as a parameter to supply to the STL transform() function? > > You don't. [...] > > string lowercase ( string const s ) { > > string lower(s); > > for (size_t i = 0; i < s.length(); ++i) { > > lower[i] = tolower(lower[i]); > > } > > return lower; > > } > > int main(int argc, char* argv[]) { > > if (argc > 1) { > > ifstream in(argv[1]); > > vector<string> vs; > > copy(istream_iterator<string>(in), > > istream_iterator<string>(), > > back_inserter(vs)); > > transform(vs.begin(), vs.end(), vs.begin(), &lowercase); > > sort(vs.begin(), vs.end()); > > vector<string>::iterator it = > > unique(vs.begin(), vs.end()); > > vs.resize(it - vs.begin()); > > copy(vs.begin(), vs.end(), > > ostream_iterator<string>(cout, "\n")); } > > } > > Now, which way is better in which ways is a different matter. > Is there actually any difference at all (if we except the > passing by copy in your implementation) ? One small difference: if you use a functional object, each different function has a different type, so the compiler will have to generate a distinct instantiation of the transform function template for each different function you pass. All of the pointers to function have the same type, so there is only one instantiation. Note that this means that with the functional object, the compiler may be able to inline the function, and even if it doesn't, it is a call to a fixed address, not through an indirection. So you may get slightly more speed in return for the code bloat. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
On Dec 11, 11:26 am, James Kanze <james.ka...@gmail.com> wrote:
> On Dec 11, 10:37 am, mathieu <mathieu.malate...@gmail.com> wrote: > > > On Dec 11, 2:28 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote: > > > Alex Buell wrote: > > > > I've just written the below as an exercise (don't worry about the lack > > > > of checking), but I was wondering why I needed to write a struct with > > > > an operator() as a parameter to supply to the STL transform() function? > > > You don't. > > [...] > > > > > > string lowercase ( string const s ) { > > > string lower(s); > > > for (size_t i = 0; i < s.length(); ++i) { > > > lower[i] = tolower(lower[i]); > > > } > > > return lower; > > > } > > > int main(int argc, char* argv[]) { > > > if (argc > 1) { > > > ifstream in(argv[1]); > > > vector<string> vs; > > > copy(istream_iterator<string>(in), > > > istream_iterator<string>(), > > > back_inserter(vs)); > > > transform(vs.begin(), vs.end(), vs.begin(), &lowercase); > > > sort(vs.begin(), vs.end()); > > > vector<string>::iterator it = > > > unique(vs.begin(), vs.end()); > > > vs.resize(it - vs.begin()); > > > copy(vs.begin(), vs.end(), > > > ostream_iterator<string>(cout, "\n")); } > > > } > > > Now, which way is better in which ways is a different matter. > > Is there actually any difference at all (if we except the > > passing by copy in your implementation) ? > > One small difference: if you use a functional object, each > different function has a different type, so the compiler will > have to generate a distinct instantiation of the transform > function template for each different function you pass. All of > the pointers to function have the same type, so there is only > one instantiation. > > Note that this means that with the functional object, the > compiler may be able to inline the function, and even if it > doesn't, it is a call to a fixed address, not through an > indirection. So you may get slightly more speed in return for > the code bloat. Thanks ! -Mathieu |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
On Dec 11, 1:24 am, Alex Buell <alex.bu...@munted.org.uk> wrote:
> I've just written the below as an exercise (don't worry about > the lack of checking), but I was wondering why I needed to > write a struct with an operator() as a parameter to supply to > the STL transform() function? Since no one has mentioned it yet... [...] > struct lowercase > { > string operator()(const string& s) > { > string lower(s); > for (size_t i = 0; i < s.length(); ++i) > lower[i] = tolower(lower[i]); This line, of course, results in undefined behavior on implementations where plain char is signed. If you insist on using the functions in <cctype> (instead of those in <locale>---admittedly much more awkward), then you must cast: lower[ i ] = tolower( static_cast< unsigned char >( lower[ i ] ) ; And the usual reminder that this doesn't work in all (or even most) languages: there's not always a one to one mapping of lower to upper, or vice versa. > return lower; > } > }; -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
![]() |
| Outils de la discussion | |
|
|