i'm building a class with std::function for recive several parameters or none:

class event2
{
public:
    typedef std::function<void(...)> OnSomethingHandler;


    void operator() (...)
    {
        eventwithoutarg (...);
    }

    event & operator = (OnSomethingHandler Handler(...))
    {
        eventwithoutarg(...) = Handler(...);
        return *this;
    }

private:
    OnSomethingHandler eventwithoutarg(...);
};

what i'm doing wrong with '...'?

Recommended Answers

All 11 Replies

Here is an article about elipses. There must be at least one parameter before the elipses. For example:
void foo(int x, ...);

As far as I know, the standard does not provide a specialization of std::function for "variadic functions" (also called "variable argument functions", or just var-arg functions). When you use the ellipses alone (not part of a variadic template syntax), it declares a variadic function, which is a special kind of function that was inherited from C to allow for a variable amount of parameters (e.g., to allow the implementation of functions like printf or scanf).

I am not too surprised that the standard committee overlooked this possibility since variadic functions are antiquated and unsafe. It is generally not recommended to use them, ever. And one of the main purposes of variadic templates is to replace variadic functions with a type-safe solution. In other words, forget about variadic functions, they are just part of the C legacy that C++ has to drag around.

If variadic functions could be used with std::function, your code would have to look like this:

class event2
{
public:
    typedef std::function<void(...)> OnSomethingHandler;


    template <typename... Args>
    void operator() (Args&&... args)
    {
        eventwithoutarg(std::forward<Args>(args)...);
    }

    event & operator = (OnSomethingHandler Handler)
    {
        eventwithoutarg = Handler;
        return *this;
    }

private:
    OnSomethingHandler eventwithoutarg;
};

Except that this will not work because the type std::function<void(...)> is not defined by the standard (AFAIK).

If I understand what you are trying to do, I think you need to do a classic type-erasure strategy. Here is what I mean:

class events {
  private:
    // have a placeholder base-type:
    struct base {
      virtual ~base();
    };

    // have a derived type to wrap the 
    //  actual functor object:
    template <typename... Args>
    struct wrapped : base {
      typedef std::function<void(Args...)> func_type;

      func_type f;

      wrapped(func_type aFunc) : f(aFunc) { };
    };

    // Hold a base-type pointer:
    std::unique_ptr<base> p_base;

  public:

    // Initialize object with any function:
    template <typename... Args>
    events(std::function<void(Args...)> aFunc) :
           p_base(new wrapped<Args...>(aFunc)) { };

    // Assign object with any function:
    template <typename... Args>
    events& operator=(std::function<void(Args...)> aFunc) {
      p_base = std::unique_ptr<base>(new wrapped<Args...>(aFunc));
      return *this;
    };

    // Call the function by casting the base
    //  pointer back to its derived type:
    template <typename... Args>
    void operator()(Args... args) const {
      wrapped<Args...>* p_wrapped = dynamic_cast< wrapped<Args...>* >(p_base.get());
      if(p_wrapped) // <- if cast successful
        p_wrapped->f(args...);
      else
        throw std::runtime_error("Invalid arguments to function object call!");
    };
};

The basic features here is that you can create / assign-to the events objects with any function type whatsoever (as long as it returns void, but that could also be fixed easily). And you can call the events object (the call operator) with any arguments. And if the arguments do not match (the arguments provided to the call, and those of the underlying function object), then it throws an exception at run-time. The drawbacks here is that there is run-time overhead (dynamic allocation, and dynamic-casting), and you can only catch errors at run-time (as opposed to compile-time).

Notice here that the trade-off for using a type-erasure technique is that you can only detect the error at run-time, but you get the advantage that the events class does not carry the template arguments of the function type (i.e., the type-dependency is erased).

This is far superior to the "variadic function" version that you initially attempted because it will, at least, catch errors at run-time. With the variadic function version, you will not be able to catch any error, instead, you'll just corrupt the whole program's memory, if the wrong arguments are provided (which is why variadic functions are discouraged). Not to mention that your variadic function version would only work for variadic functions, not any functions.

So, these are your basic options. (1) Have the events class depend on the argument types of the function, which allows you to catch all mismatching errors at compile-time, but you have to carry that "baggage". (2) Have the events class do a type-erasure on the function's type, which means you can (at best) catch mismatching errors at run-time, but you no longer have to carry the "baggage" over to the events class. By "baggage", I mean the set of argument types for the function.

1 thing: a functor is a variable that we can use lambda or call another function, right?

No. A functor is just a short for "function object" or "callable object". It is a callable thing. For example, this is a functor:

struct Foo {
  void operator()() const { };
};

Because if you have an object declared as something like Foo f;, then you can "call" it, as in, you can do f();.

Technically, almost anything that is callable is a "functor". A function pointer is a functor, because it is an object (a pointer is a variable, which is an object) and it is callable. A lambda expression is a functor too. The standard class template std::function is a functor too, with the special feature that it can encapsulate any other functor you give it.

Traditionally, however, the term functor is mostly used to describe an object of a class like the "Foo" class in the above snippet. In other words, an object of a class that has a "call operator", i.e. the operator(). But in modern C++, with things like std::function, std::bind and lambdas, that line has become a bit more blurred. I just use the term "functor" for any object that is callable.

i just have 1 question: the foo structure accept parameters?
how can i change the funtion?

the foo structure accept parameters?

No. The call operator definition is as follows:

void operator()() const { };

Which means:
void: This function has no return value.
operator(): This function is invoked by "calling" the object like you would call a function.
(): This function takes no parameters.
const: This function does not modify the object on which it is called.
{ };: This is the function body (which I left empty).

So, the answer is: No, an functor of type "Foo" is called with no parameters.

how can i change the funtion?

What do you mean? I left the body of the function empty, but, of course, you would normally write code in that function-body. If that's what you mean by "change the function", then that's that, i.e., you can change the function when you open the source file in a text editor or IDE and you write code in the function-body.

If you mean to somehow assign the call operator to trigger the call of some other function, then that's impossible in this code. In C++, a function is just a function, you cannot "change" it in that sense. If you have a variable like a function-pointer or a std::function object, then this is different, these are variables that are meant to be changed to whatever value you want. A "function" is not a variable, it's immutable (cannot be changed).

I'm gonna be frank here, I must say that you seem be way over your head right now. I think you threw yourself in the deep end of C++, and you are starting to get lost. On the one hand, you are trying to do very advanced things (like type-erased generic callbacks with variadic parameters). And on the other hand, you seem to struggle with (1) basic C++ syntax (like the declaration of the call operator for this Foo class), (2) basic C++ concepts (like "functors"), and (3) basic C++ rules (like "no expressions at global/namespace scope"). It just feels weird to me to explain some advanced technique in one post and then explain some very basic concept the next post. So, I would advise that you "calm down" a bit and try to have more modest goals, until your knowledge of C++ gets a bit more solid.

with your code i did:

struct event
{
    void operator()(...)  { };
};



#include <iostream>
#include <string>
#include "events.h" //wehre is the structure

using namespace std;

class test
{
    public:
    event Soma(int a, int b);
    void write(string a)
    {
        cout << a;

        Soma(4,5);
    }
};

test a;


int main()
{
    a.Soma(int a, int b)
    {
        cout<<"\nMessage Printed\n" ;
    };
    a.write("hello world");
    cin.get();
    return 0;
}

but i get errors when i change the Soma()

"C:\Users\Joaquim\Documents\CodeBlocks\My Class\main.cpp|24|error: expected primary-expression before 'int'|"

This speaks to the point I made in the last post. The code you just posted makes no sense at all.

And obviously, when I posted the simple example of what a "functor" is, I didn't mean that as a suggestion for something to try for your specific problem. It was just the simplest possible example I could come up with of something that can be called a "functor", to illustrate the concept. It had nothing to do with your specific problem. You asked for an explanation of what a "functor" is, and I delivered that. A functor is a very general and fundamental concept in C++, and so, I had to explain it in very general terms, having nothing to do directly with your specific problem.

but i get errors when i change the Soma()

What do you mean?!?!? You cannot "change the Soma()". That makes no sense at all. A function has one definition and only one definition (that's the fundamental C++ rule, called the "One Definition Rule"). That definition is fixed during compilation, and can never be changed after that.

You can create a variable that points to a function, that's called a function-pointer. You can create a variable of a class type like std::function which can be made to point to any callable "something". But these are always just pointing to a function which has one unique and immutable definition.

And the error itself is due to this syntax:

a.Soma(int a, int b)
{
    cout<<"\nMessage Printed\n" ;
};

which is completely erroneous. The syntax looks like a cross between a local function definition (which is not allowed) and a call to the member function Soma (which cannot shouldn't have the "int" types, only the variables that you want to pass to the function call).

I cannot make any sense of it, nor can the compiler. Again, I repeat, you need to get a more solid grasp of the basic rules of C++ before you go too deep and try to do crazy things.

continue just with std::function:
if these is legal: std::function<void(...)> create(int a, int b);, why i can't do: create(2,3);???
errors messages:

"C:\Users\Joaquim\Documents\CodeBlocks\events13\main.cpp||In member function 'void test::write(std::string)':|
C:\Users\Joaquim\Documents\CodeBlocks\events13\main.cpp|14|error: invalid use of incomplete type 'class std::function<void(...)>'|
c:\program files\codeblocks\mingw32\lib\gcc\i686-w64-mingw32\4.8.1\include\c++\functional|1866|error: declaration of 'class std::function<void(...)>'|
||=== Build finished: 2 errors, 0 warnings (0 minutes, 1 seconds) ===|"

some persons don't advice use macros.... please someone tell me why.
but heres a nice code that i did with some help:

#include <iostream>
#include <functional>

#define event(eventname, ... ) std::function<void(__VA_ARGS__ )> eventname

using namespace std;

class test
{
    public:
    event(moved,(int a,int b)) ;
    event (created) ;
    event(hello);

    void write(string a)
    {
        cout << a;
        moved(2,3);
        created();
    }
};

void a_hello()
{
    cout << "\nhello mother\n";
}

int main()
{
    test a;
    a.moved=[](int a, int b)
    {
        cout << "\nmoved\n" << a+b << "\n";
    };
    a.hello=&a_hello;
    a.created=[]()
    {
        cout << "\nbye\n";
    };
    a.write("oi\n");
    a.hello();
    return 0;
}

i love these way for put the parameters, very cool.
and see the way that i create the macro, can be realy dificulty at 1st, but it's very nice.
readers imagine the a_hello have some parameters, so we must declare it like the move and when we call it, we use arguments.
heres a nice link about Variadic Macros: http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

anotherthing: if you need a create event with a class, declare it in construtor parameter.
i hope everyon enjoy with these nice code;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.