Generic member functors

View: New views
4 Messages — Rating Filter:   Alert me  

Generic member functors

by Peter Basista :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.
Hello,

I have been trying to use sigc++ library to make a kind of a generic member functor, but I didn't succeed.

Basically, I would like to create a functor, to which I would be able assign arbitrary member functions of any class derived from a previously chosen base class. I tried this, but with not much luck. I am attaching a simple example where I would like to show what exactly I mean.

I hope that something like this is possible with sigc++.

I have also come across several ambiguities with sigc++, which are commented in the source file. I don't understand the behavior of sigc++ there, and I marked these spots, so you can look at them.

Thank you all in advance.


Get news, entertainment and everything you care about at Live.com. Check it out!

/** If you have pkg-config, then you can compile this file for example like this:
 * c++ -Wall `pkg-config --cflags --libs sigc++-2.0` sigcpp.cpp
 */

#include <iostream>
#include <sigc++/sigc++.h>

class Parent {
public:
        int f (int i, double d, char c);
};

int Parent::f (int i, double d, char c) {
        std::cout << "Parent::f" << std::endl;
        return 0;
}

class Child : public Parent {
public:
        int g (int i, double d, char c);
};

int Child::g (int i, double d, char c) {
        std::cout << "Child::g" << std::endl;
        return 0;
}

typedef sigc::slot<int, Parent *, int, double, char> sp;

typedef sigc::slot<int, Child *, int, double, char> sch;

typedef sigc::mem_functor3<int, Parent, int, double, char> mfp;

typedef sigc::mem_functor3<int, Child, int, double, char> mfch;

typedef sigc::mem_functor4<int, Parent, int, double, char, char *> mfp4;

typedef sigc::mem_functor4<int, Child, int, double, char, char *> mfch4;

int foo (void) {
        Parent p;
        Child ch;

        mfp a_p = sigc::mem_fun(& Parent::f); // <-- This works.
        a_p(& p, 0, 1.0, 'c'); /// <-- Works
        a_p(& ch, 0, 1.0, 'c'); /// <-- Works

// mfp a_ch = sigc::mem_fun(& Child::g); // <-- Doesn't work, which seems strange.
// Compile error: conversion from ‘sigc::mem_functor3<int, Child, int, double, char>’ to non-scalar type ‘mfp’ requested

// mfch b_p = sigc::mem_fun(& Parent::f); // <-- Doesn't work, but this seems correct, because of conversion from Parent to Child.
// Compile error: conversion from ‘sigc::mem_functor3<int, Parent, int, double, char>’ to non-scalar type ‘mfch’ requested

        mfch b_ch = sigc::mem_fun(& Child::g); // <-- This works.
// b_ch(& p, 0, 1.0, 'c'); /// <-- Doesn't work, but this is OK.
// Correctly displayed error message: invalid conversion from ‘Parent*’ to ‘Child*’
        b_ch(& ch, 0, 1.0, 'c'); /// <-- Works

        sp c_p = sigc::mem_fun(& Parent::f); ///  <-- This works
        c_p(& p, 0, 1.0, 'c'); /// <-- Works
        c_p(& ch, 0, 1.0, 'c'); /// <-- Works

// sp c_ch = sigc::mem_fun(& Child::g); ///  <-- This does not work, which seems also strange.
// Compile error: invalid conversion from ‘Parent* const’ to ‘Child*’

        sch d_p = sigc::mem_fun(& Parent::f); ///  <-- This compiles, which is strange.
// d_p(& p, 0, 1.0, 'c'); // <-- But this refuses to compile, which is correct.
//      Correctly displayed error message: invalid conversion from ‘Parent*’ to ‘Child*’
        d_p(& ch, 0, 1.0, 'c'); // <-- Works

        sch d_ch = sigc::mem_fun(& Child::g); ///  <-- This works
// d_ch(& p, 0, 1.0, 'c'); /// <-- Doesn't work, but this is OK.
// Correctly displayed error message: invalid conversion from ‘Parent*’ to ‘Child*’
        d_ch(& ch, 0, 1.0, 'c'); /// <-- Works
       
        // I would like to ask for explnation of how to work-around this previously mentioned error:
        //
        // Error: invalid conversion from ‘Parent* const’ to ‘Child*’
        //
        // First, why the `const` is added there?
       
        /** I agree that this error is in some way reasonable and I know that this usage of functors is not exactly correct.
         *  But is there a correct usage, then?
         *  
         *  What I would like to achieve:
         *  
         *  Have a generic functor, to which I would be able to assign a member function
         *  of arbitrary class derived from the previously specified base class. The only limitations
         *  would be the number of parameters and the type of parameters. I would also like to be able
         *  to alter the number of parameters as well as their type by standard means of sigc++ library.
         *  
         *  The most important is that I would like this functor to behave as the unbound member functor,
         *  so I would be able to choose the instance from which the member function will be called.
         *
         *  How can I achieve something like this?
         */
       
        return 0;
}

int main (int argc, char ** argv) {
        std::cout << foo() << std::endl;
        return 0;
}


_______________________________________________
libsigc-list mailing list
libsigc-list@...
http://mail.gnome.org/mailman/listinfo/libsigc-list

Re: Generic member functors

by klaus triendl-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

JinXXXX Kili Billl schrieb:

> Hello,
>
> I have been trying to use sigc++ library to make a kind of a generic
> member functor, but I didn't succeed.
>
> Basically, I would like to create a functor, to which I would be able
> assign arbitrary member functions of any class derived from a previously
> chosen base class. I tried this, but with not much luck. I am attaching
> a simple example where I would like to show what exactly I mean.
>
> I hope that something like this is possible with sigc++.
>
> I have also come across several ambiguities with sigc++, which are
> commented in the source file. I don't understand the behavior of sigc++
> there, and I marked these spots, so you can look at them.

There are no ambiguities with sigc++. There are templates involved, so
you can't e.g. assign a mem_functor typed for a child to a mem_functor
typed for a Parent. And I think you are mixing slots and functors...

A slot represents a callable entity, no matter what functor is behind.
So, a slot is the generic functor you want to have (only knowing about
the return type and parameters, but loosing compile-time information
about the original functor).
What you want to do is the following:

<code>
Parent p;
Child c;

sigc::slot<int, Parent*, int, double, char> myclosure;

myclosure = sigc::mem_fun(&Parent::f);
const int ret1 = myclosure(&p, 0, 1.0, 'c');

myclosure = sigc::mem_fun(&Child::g);
const int ret2 = myclosure(&c, 0, 1.0, 'c');
</code>


Klaus Triendl
_______________________________________________
libsigc-list mailing list
libsigc-list@...
http://mail.gnome.org/mailman/listinfo/libsigc-list

Re: Generic member functors

by Peter Basista :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.
Hello Klaus,

> There are no ambiguities with sigc++. There are templates involved, so
> you can't e.g. assign a mem_functor typed for a child to a mem_functor
> typed for a Parent. And I think you are mixing slots and functors...

I am sorry, you are apparently right.


> A slot represents a callable entity, no matter what functor is behind.
> So, a slot is the generic functor you want to have (only knowing about
> the return type and parameters, but loosing compile-time information
> about the original functor).

Thank you very much for explaining this to me. It is precisely what I need.

> What you want to do is the following:

> <code>
> Parent p;
> Child c;

> sigc::slot<int, Parent*, int, double, char> myclosure;

> myclosure = sigc::mem_fun(&Parent::f);
> const int ret1 = myclosure(&p, 0, 1.0, 'c');

> myclosure = sigc::mem_fun(&Child::g); <-- Error line
> const int ret2 = myclosure(&c, 0, 1.0, 'c');
> </code>


> Klaus Triend

Does this code compile for you? I just did copy and paste and tried to compile the above code. The result was:

error: invalid conversion from ‘Parent* const’ to ‘Child*’

This is the same error I described before in the attached file.

So, if this is the right way to cope with my problem, why it refuses to compile?



But anyway, thank you for a brief and valuable response.
Now I at leas understand better what is what ...


See all the ways you can stay connected to friends and family
_______________________________________________
libsigc-list mailing list
libsigc-list@...
http://mail.gnome.org/mailman/listinfo/libsigc-list

Re: Generic member functors

by klaus triendl-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

JinXXXX Kili Billl schrieb:

>> <code>
>> Parent p;
>> Child c;
>>
>> sigc::slot<int, Parent*, int, double, char> myclosure;
>>
>> myclosure = sigc::mem_fun(&Parent::f);
>> const int ret1 = myclosure(&p, 0, 1.0, 'c');
>>
>> myclosure = sigc::mem_fun(&Child::g); <-- Error line
>> const int ret2 = myclosure(&c, 0, 1.0, 'c');
>> </code>
>
> Does this code compile for you? I just did copy and paste and tried to
> compile the above code. The result was:
>
> error: invalid conversion from ‘Parent* const’ to ‘Child*’

Sorry, my fault, I didn't try to compile it.


> So, if this is the right way to cope with my problem, why it refuses to
> compile?

Because in the end the slot must call the functor stored in the slot
(the functor that you assign to the slot).
The function slot4<int, Parent*, int double, char>::call_it() calls the
mem_functor3<int, Child*, int, double, char> with the parameter types
(int, Parent*, int, double, char) - Parent* is not convertible to Child*
or Child&.


You have 2 possibilities:

1) make g() [pure] virtual in Parent to get polymorphic runtime behaviour.
If you need to be totally flexible about the object instance during
runtime then this is the right solution.

2) Rather use mem_fun() to bind the object instance than specifying the
instance when calling the slot.
If you can decide already at compile time which object instance to use
then you can use this solution.


Here is some code to show what I mean:
1)
<code>
class Parent
{
public:
  int f(int, double, char)
  {
    return 0;
  }

  virtual int g(int, double, char) = 0;
};

class Child: public Parent
{
public:
  // virtuals from Parent
  virtual int g(int, double, char)
  {
    return 0;
  }
};

// somewhere else:
Parent p;
Child c1, c2;
sigc::slot<int, Parent*, int, double, char> myclosure;

myclosure = sigc::mem_fun(&Parent::f);
// call p->f()
myclosure(&p, 0, 1.0, 'c');

myclosure = sigc::mem_fun(&Parent::g);
// call c1->g()
myclosure(&c1, 0, 1.0, 'c');
// call c2->g()
myclosure(&c2, 0, 1.0, 'c');
</code>


2)
<code>
class Parent
{
public:
  int f(int, double, char)
  {
    return 0;
  }
};

class Child: public Parent
{
public:
  int g(int, double, char)
  {
    return 0;
  }
};


// somewhere else
Parent p;
Child c1, c2;
sigc::slot<int, int, double, char> myclosure;

// call p->f()
myclosure = sigc::mem_fun(&p, &Parent::f);
myclosure(0, 1.0, 'c');

// call c1->g()
myclosure = sigc::mem_fun(&c1, &Child::g);
myclosure(0, 1.0, 'c');

// call c2->g()
myclosure = sigc::mem_fun(&c2, &Child::g);
myclosure(0, 1.0, 'c');
</code>



Klaus
_______________________________________________
libsigc-list mailing list
libsigc-list@...
http://mail.gnome.org/mailman/listinfo/libsigc-list