Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 A Test
Index -> Programming, C++ -> C++ Tutorials
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: Tue Oct 31, 2006 4:30 pm   Post subject: A Test

Without compiling the following code, predict its output.

code:
#include <functional>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
#include <ext/functional>

using namespace std;
using __gnu_cxx::compose1;

int main()
{
   vector<int> v;
   v.push_back(1);
   v.push_back(2);

   vector<int> v2;

   transform(v.begin(), v.end(), back_inserter(v2),
             compose1(bind2nd(multiplies<int>(), 2),
                      negate<int>()));

   copy(v2.begin(), v2.end(), ostream_iterator<int>(cout, "\n"));
}
Sponsor
Sponsor
Sponsor
sponsor
r.3volved




PostPosted: Tue Oct 31, 2006 5:10 pm   Post subject: (No subject)

not sure what this does exactly:
compose1( bind2nd( multiplies<int>(), 2 ), negate<int>() )

I imagine it does some calculation on the value stored in each element of v and applies the modified v element to v2 as it's calculated, then prints the vector of v2.

Is compose1 something you've created?
I'd hope it's not an STL naming convention.
wtd




PostPosted: Tue Oct 31, 2006 5:37 pm   Post subject: (No subject)

The compose1 function is a convenient way of creating a UnaryCompose function object. It is an SGI extension to the STL, but GCC includes it via the "ext/functional" header, and it resides in the __gnu_cxx namespace.
abcdefghijklmnopqrstuvwxy




PostPosted: Sun Jan 21, 2007 5:46 am   Post subject: RE:A test

At first glance I had no idea what this thing could possibly output. Then I thought it was a trick question cause I didn't see "cout" anywhere. But then I found "cout" and realized it does print something... Then I started writing my thoughts in this post and I came to an answer, although not a confident one...

Quote:

The compose1 function is a convenient way of creating a UnaryCompose function object.


So, in beginners terms, compose1 takes two functions and makes them into one? If so, I doubt it just joins them together. How does it work?

code:

back_inserter(v2)


I looked up this function and found: "Creates an iterator that can insert elements at the back of a specified container." So in this case won't it return v2.begin()?

code:

bind2nd(multiplies<int>(), 2)


Normally I would scratch my head. multiplies() takes no arguments so how does it know what to multiply by? Then I noticed the "bind2nd" and I figure it means, bind the 2 to multiplies. So I'm guessing this means multiply by 2. Or at least it should if code has any purpose whatsoever... I mean why not code in binary if we are going to code obfuscatedly?

code:

compose1(bind2nd(multiplies<int>(), 2),
                      negate<int>()));


if both functions are carried out. we've multiplied and then made each number negative.

So the output is:

code:

-2
-4
ownageprince




PostPosted: Sun Jan 21, 2007 9:36 am   Post subject: Re: A Test

v.push_back(1);
v.push_back(2);

this the numbers by which

transform(v.begin(), v.end(), back_inserter(v2),
compose1(bind2nd(multiplies<int>(), 2), <- the two will by multiplied
negate<int>())); <- I am guessing this makes it negative because it is silly to think that something would be "negated"
copy(v2.begin(), v2.end(), ostream_iterator<int>(cout, "\n")); <- displays the product of the two multiplication problems.
wtd




PostPosted: Sun Jan 21, 2007 9:40 am   Post subject: Re: RE:A test

abcdefghijklmnopqrstuvwxy @ Sun Jan 21, 2007 6:46 pm wrote:
At first glance I had no idea what this thing could possibly output. Then I thought it was a trick question cause I didn't see "cout" anywhere. But then I found "cout" and realized it does print something... Then I started writing my thoughts in this post and I came to an answer, although not a confident one...

Quote:

The compose1 function is a convenient way of creating a UnaryCompose function object.


So, in beginners terms, compose1 takes two functions and makes them into one? If so, I doubt it just joins them together. How does it work?


Imagine you have two mathematical functions:

code:
a(x) = 2x
b(x) = x - 1


Now, let's create a third.

code:
c(x) = 2x - 1


And now, let's create a fourth.

code:
compose(g, f, x) = g(f(x))


We can now create a function equivalent to c.

code:
c'(x) = compose(b, a, x)


Does it make any more sense now? Smile

abcdefghijklmnopqrstuvwxy @ Sun Jan 21, 2007 6:46 pm wrote:
code:
back_inserter(v2)


I looked up this function and found: "Creates an iterator that can insert elements at the back of a specified container." So in this case won't it return v2.begin()?


Not at all. The back_inserter function creates an iterator object, which holds the container passed to it as a reference. A function can then use that iterator to insert values into that container.[/quote]

abcdefghijklmnopqrstuvwxy @ Sun Jan 21, 2007 6:46 pm wrote:
code:

bind2nd(multiplies<int>(), 2)


Normally I would scratch my head. multiplies() takes no arguments so how does it know what to multiply by? Then I noticed the "bind2nd" and I figure it means, bind the 2 to multiplies. So I'm guessing this means multiply by 2. Or at least it should if code has any purpose whatsoever... I mean why not code in binary if we are going to code obfuscatory?


First off, let me reassure you that there's nothing obfuscated about this. It is in fact one of the cleanest pieces of C++ you will ever see, considering what's going on under the surface.

You see, multiplies isn't a function as used here. It's a constructor. It create a binary function object. That is, an object which, when it's () operator is called with two integer arguments, returns an integer result. When I call bind2nd, I'm binding a value to the second argument of that binary function, and in the process, creating a unary function. The new unary function object takes a single integers, multiplies it by two and returns that value.

abcdefghijklmnopqrstuvwxy @ Sun Jan 21, 2007 6:46 pm wrote:

code:

compose1(bind2nd(multiplies<int>(), 2),
                      negate<int>()));


if both functions are carried out. we've multiplied and then made each number negative.

So the output is:

code:

-2
-4


Bingo. The important thing, though, is understanding why this works, and why it's elegant, and not obfuscatory.
abcdefghijklmnopqrstuvwxy




PostPosted: Sun Jan 21, 2007 9:10 pm   Post subject: RE:A test

I don't understand why it works and why it's elegant, but I'm going to try!
wtd




PostPosted: Sun Jan 21, 2007 9:32 pm   Post subject: RE:A test

A first question would be whether or not you understand function objects.
Sponsor
Sponsor
Sponsor
sponsor
abcdefghijklmnopqrstuvwxy




PostPosted: Sun Jan 21, 2007 11:28 pm   Post subject: RE:A test

I've never heard of them until this post.
wtd




PostPosted: Sun Jan 21, 2007 11:40 pm   Post subject: RE:A test

Consider a very simple function object:

code:
struct int_add
{
   int operator()(int a, int b) const;
};

int int_add::operator()(int a, int b) const
{
   return a + b;
}
abcdefghijklmnopqrstuvwxy




PostPosted: Sun Jan 21, 2007 11:50 pm   Post subject: RE:A test

So compose1 takes two function objects as its parameter. we wanted to multiply each element by two and then negate them. So we use the multiply<int> which is a type and with the overloaded () operator that takes two integers, the second is binded as two, and the first param receives its integers from transform().

I just don't see why a function object is used instead of a function... or two functions... one to multiply and the other to negate.
wtd




PostPosted: Mon Jan 22, 2007 12:05 am   Post subject: RE:A test

Well, with functions in C++, there's no way to create a new function without giving it a name. But, we can create objects, and pass them to fucntions, without ever giving a name to that object. And that object can be used like a function.

In the test's example, we first have to take the templated multiplies class and create an instance of it. This actually gives us a concrete "multiplies<int>" class to work with.

code:
multiplies<int>()


We call its constructor to create a new instance of that class. Yay! We have a function object.

But, this function object takes two parameters. The compose1 function expects function objects that take a single parameter.

code:
bind2nd(multiplies<int>(), 2)


So we take that object and we pass it to the bind2nd function, which creates a new function object that takes one parameter.

Now, we have something that can be passed to compose1.
abcdefghijklmnopqrstuvwxy




PostPosted: Mon Jan 22, 2007 12:22 am   Post subject: RE:A test

Okay I can understand that a little bit better. The part that vexes me is: multiplies<int>().

Normally when you call the constructor you create an instance. So how does this both call the constructor and call the overloaded operator()?

Another thing is how does the first parameter get passed to the overloaded operator()?

Say multiplies<int>() was a unary function object without bind2nd. How would the code be written in that case? Is it the same thing just without bind2nd? If it is, than that means transform passes the parameter to the unary function object somehow?

Could you explain this to me? taken from http://en.wikipedia.org/wiki/Function_object

code:


An advantage of function objects in C++ is performance because unlike a function pointer, a function object can be inlined. For example, consider a simple function which increments its argument implemented as a function object:

struct IncrementFunctor {
  void operator()(int&i) { ++i; }
}

and as a free function:

void increment_function(int&i) { ++i; }

Recall the standard library function std::for_each():

template<typename InputIterator, typename Function>
Function for_each(InputIterator first, InputIterator last, Function f) {
  for ( ; first != last; ++first)
    f(*first);
  return f;
}

Suppose we apply std::for_each() like so:

int A[] = {1, 4, 2, 8, 5, 7};
const int N = sizeof(A) / sizeof(int);
for_each(A, A + N, IncrementFunctor());
for_each(A, A + N, increment_function);

Both calls to for_each() will work as expected. The first call will be to this version:

IncrementFunctor for_each<int*,IncrementFunctor>(int*, int*, IncrementFunctor)

the second will be to this version:

void(*)(int&) for_each<int*,void(*)(int&)>(int*, int*, void(*)(int&))

Within for_each<int*,IncrementFunctor>(), the compiler will be able to inline the function object because the function is known at compile time whereas within for_each<int*,void(*)(int&)>() the function cannot be known at compile time and so cannot be inlined.

wtd




PostPosted: Mon Jan 22, 2007 10:55 am   Post subject: Re: RE:A test

abcdefghijklmnopqrstuvwxy @ Mon Jan 22, 2007 1:22 pm wrote:
Okay I can understand that a little bit better. The part that vexes me is: multiplies<int>().

Normally when you call the constructor you create an instance. So how does this both call the constructor and call the overloaded operator()?


One step at a time.

This does not call the overloaded () operator. It is simply calling the constructor.

The overloaded () operator is called on the instance that the constructor creates.
Display posts from previous:   
   Index -> Programming, C++ -> C++ Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 14 Posts ]
Jump to:   


Style:  
Search: