oops
oops

Reputation: 93

Could you explain the mixture of many kinds of operands below? (C++)

I've checked someone's code through a tool, and it said that there is a problem here:

policyCallback = callback;

I cannot find the problem since I'm a beginner. Could you give me a hint or guide to translate it?

The entire code is below.

std::function <void (std::vector<std::string> resources)> policyCallback;

namepace nsp {
class Manager {
public:
  Manager(const std::string &str);
  virtual ~Manager();

  template <typename FuncType>
  void registerPolicyActionCallback(FuncType callback) {
    policyCallback = callback;
  }
};
} //namespace nsp

namespace nsp{
class Manager;
}

class SomeAPIs {
public:
  void policyActionCallback(std::vector<std::string> param);
};

int main() {
  nsp::Manager *rManager; 

  rManager->registerPolicyActionCallback(std::bind(&SomeAPIs::policyActionCallback, this, std::placeholders::_1)); 
}

Upvotes: 2

Views: 105

Answers (2)

RobClucas
RobClucas

Reputation: 855

Besides some obvious errors in the code, the main problem preventing you from achieving what you want is the way in which you are calling std::bind.

Firstly, your code declares policyActionCallback(/*...*/) private in SomeAPIs. Now while you can call any member function via a pointer to it, regardless of it being public, protected, or private, only members and friends can create a pointer to a private member function. So unless you call std:bind from within the API itself, or a friend of the API, you will only be able to bind to public member functions of the API. For the sake of demonstrating a working concept, I will assume that the functions you want to use for callback are all public members of the API.

Secondly, to bind a member function using std::bind, you need to provide a reference to the function (which you did), as well a reference (or pointer) to an instance of the class to which the member belongs, which you have not done.

Therefore, since the function you want to bind to is a member of SomeAPIs, you need to give a reference to an instance of SomeAPIs. I'm assuming that you intended this to be a pointer to the nsp::Manager instance, which, as I have just explained, is the wrong object to provide a reference to.

Additionally, your use of the this keyword is incorrect. Taken from cppreference, this can appear in the following contexts

  1. Within the body of any non-static member function, including member initializer list
  2. Within the declaration of a non-static member function anywhere after the (optional) cv-qualifier sequence, including dynamic exception specification(deprecated), noexcept specification(C++11), and the trailing return type(since C++11)
  3. Within default member initializer (since C++11)

Since your use of this fits non of the above, the compiler gives:

error: invalid use of 'this' in non-member function

Here is working code for what you are wanting to achieve. Note how std::bind is now used. (I have added a constructor for Manager, removed the virtual destructor since manager does not have any virtual function, made the function in SomeAPIs public so that std::bind can receive a pointer to it, and deleted the nsp::Manager pointer which now is declared on the free store):

#include <vector>
#include <iostream>
#include <functional>

std::function <void (std::vector<std::string> resources)> policyCallback;

namespace nsp {
    class Manager {
    public:
      Manager() {};
      Manager(const std::string &str) {}

      // Don't know why this is virtual when this isn't a base class?
      // virtual ~Manager();

      template <typename FuncType>
      void registerPolicyActionCallback(const FuncType callback) {
        policyCallback = callback;
      }
    };
} //namespace nsp

class SomeAPIs {
    public:
      void policyActionCallback(std::vector<std::string> param) {
          for (const auto& p : param) {
              std::cout << "SomeAPIs : " << p << "\n";
      }
    }
};

// Another API for illustration
class SomeOtherAPI {
    public:
      void policyActionCallback(std::vector<std::string> param) {
          for (const auto& p : param) {
              std::cout << "SomeOtherAPI : " << p << "\n";
      }
    }
};

int main() {

    // Sample resource vector for demonstration
    std::vector<std::string> resources = {"one", "two", "three"};

    // Gets rid of uninitialization error -- alternatively declare on stack
    nsp::Manager* rManager = new nsp::Manager; 

    // You need instances of an object to bind to member functions
    SomeAPIs        api1;           
    SomeOtherAPI    api2;

    // Use the first APIs function as callback
    rManager->registerPolicyActionCallback(std::bind(&SomeAPIs::policyActionCallback, &api1, std::placeholders::_1));
    policyCallback(resources);

    // Use the second APIs function as callback
    rManager->registerPolicyActionCallback(std::bind(&SomeOtherAPI::policyActionCallback, &api2, std::placeholders::_1));
    policyCallback(resources);

    delete rManager;
}

Here is a live demo.

Upvotes: 1

Radek
Radek

Reputation: 518

The snippet you provided is badly extracted copy. It confuses because the line resourceManager->registerUMSPolicyActionCallback(std::bind(&SomeAPIs::policyActionCallback, this, std::placeholders::_1)); has argument value this, it means it was called inside of a class. There should be pointer to instance of SomeAPIs.

What i meant in the comment is declaration of method registerPolicyActionCallback. It is not necessary to be a template when policyCallback cannot be anything but the only type std::function <void (std::vector<std::string> resources)>;

Anyway all the code looks good. You wrote you used tool to check code, what tool? Does it supports C++11 properly?

Upvotes: 0

Related Questions