2

I have many QActions and I would like to connect their triggered(bool) signal to a specific slot which gets an integere number as input, let's say setX(int x). I need to specify x in connect callback. For example:

connect(actionV, &QAction::triggered,
        this, &TheClass::setX /* somehow x=10 */);

I tried using std::bind and it does not work:

connect(actionV, &QAction::triggered,
        std::bind(this, &TheClass::setX, 10));
sorush-r
  • 10,490
  • 17
  • 89
  • 173
  • 4
    To begin with, you use [`std::bind`](http://en.cppreference.com/w/cpp/utility/functional/bind) wrong. The first argument is the "function" that should be called. – Some programmer dude Jul 13 '18 at 08:20
  • 1
    For this, I prefer lambdas and it's working fine (especially if receiver is not a `QObject`). e.g. `QObject::connect(actionV, &QAction::triggered, [&](bool) { setX(10); });` – Scheff's Cat Jul 13 '18 at 08:21
  • 1
    Related: https://stackoverflow.com/questions/17363003/why-use-stdbind-over-lambdas-in-c14/17545183 If you use C++14, you should avoid `std::bind` altogether. – Jaa-c Jul 13 '18 at 08:22
  • @Someprogrammerdude Oh... Yes it is wrong indeed (: Passing this as second argument, now works. Thank you – sorush-r Jul 13 '18 at 08:42

2 Answers2

4

You can solve this easily using a lambda:

connect(actionV, &QAction::triggered, [&] { 
   m_theClass.setX(10);
});
Mahmoud Badri
  • 1,256
  • 14
  • 24
2

The syntax you used for std::bind was incorrect, that's why it didn't compile.

While using a lambda is faster, I am going to post some examples using std::bind for completeness shake in the hope of being helpful to other programmers as well.

Example A:

// Declaration somewhere in a header file.
void setX(int x);

/*
 * In a cpp file:
 * Notice the order of the arguments. 
 * a) The pointer to the class member
 * b) the instance of the class (in this case is "this")
 * c) The arguments to the function are the rest.
 */
connect(actionV, &QAction::triggered, this, std::bind(&MyClass::setX, this, 10));

Now, let's pretend that you must capture the parameter of a signal. In this case it's a bool. I have to remind you, that the signature is void QAction::triggered(bool checked = false).

Example B:

// Again, declaration in a header file.
void setX(bool c, int x);

/*
 * In a cpp file:
 * Notice how the emmited bool value is captured with
 * std::placeholders::_1 and then you pass 10 as well.
 */
connect(actionV,
        &QAction::triggered,
        this,
        std::bind(&MyClass::setX, this, std::placeholders::_1, 10));

To make this even more extreme, let's pretend once again that you have two overloads of setX.

Example C:

// Declaration in a header file
void setX(bool x, int x);
void setX(int x);

/*
 * In your .cpp file:
 * a) Choose the first signature
 * b) Choose the second signature
 */
connect(actionV,
        &QAction::triggered,
        this,
        std::bind(qOverload<bool, int>(&MyClass::setX),
                  this, std::placeholders::_1, 10));
// OR

connect(actionV,
        &QAction::triggered,
        this,
        std::bind(qOverload<int>(&MyClass::setX), this, 10));

But the qOverload macro needs at least a C++14 capable compiler though. You don't want to go to:

connect(actionV,
        &QAction::triggered,
        this,
        std::bind(static_cast<void(MyClass::*)(bool, int)>(&MyClass::setX),
                  this,
                  std::placeholders::_1,
                  10));

I hope I helped a bit to clarify the syntax. I can't stress enough though that using a lambda is more efficient and simple and that this was just a fun "exercise".

Petross404
  • 177
  • 1
  • 12