can't initialize map of method pointers in c++

2019-08-04 03:58发布

问题:

I have a function like the following:

//Parser.cpp
//...
Parser::Parser(CommandFactory & fact, 
               ArrayList<std::string> & expression)
{

    operations["*"] = &fact.createMultiplyCommand; //error C2276
    operations["/"] = &fact.createAdditionCommand; //error C2276
    operations["+"] = &fact.createAdditionCommand; //error C2276
    operations["%"] = &fact.createModulusCommand; //error C2276
    operations["-"] = &fact.createSubtractionCommand; //error C2276

    infixToPostfix(fact,expression);

}
//...

//Parser.h
//...

    Parser (CommandFactory & fact,
            ArrayList<std::string> & expression);

    Stack<Command*> tempCommandStack;
    ArrayList<Command*> postfix;

    /// Destructor.
    ~Parser (void);

private:
    //syntax is: <return_type> (*)()
    //syntax for a class method is: <return_type> (<class_name> *)();
    //syntax with a typedef is: typedef <return_type> (<class_name> * <typedef_name>)();
    //                          typedef <return_type> (*<typedef_name>)()


    std::map<std::string, Command * (*)()> operations; 
    std::map<std::string,int> precedence;
//...

It also may help to know that CommandFactory is an abstract class (what is passed in is concrete)

The error I receive is C2276: '&' : illegal operation on bound member function expression.

I don't know what I'm doing wrong exactly when I define the mapping. Any ideas?

EDIT:

//CommandFactory.h
#ifndef _COMMANDFACTORY_H_
#define _COMMANDFACTORY_H_

#include "Subtract.h"
#include "Add.h"
#include "Divide.h"
#include "Multiply.h"
#include "Modulus.h"
#include "Negation.h"
class CommandFactory
{
public:

    virtual Subtract * createSubtractionCommand() = 0;
    virtual Add * createAdditionCommand() = 0;
    virtual Divide * createDivisionCommand() = 0;
    virtual Multiply * createMultiplyCommand() = 0;
    virtual Modulus * createModulusCommand() = 0;
    virtual Negation * createNegationCommand() = 0;
    ~CommandFactory(void);

};

#endif   

//StackCommandFactory.h

#ifndef _STACKCOMMANDFACTORY_H_
#define _STACKCOMMANDFACTORY_H_

#include "Add.h"
#include "Subtract.h"
#include "Divide.h"
#include "Multiply.h"
#include "Modulus.h"
#include "CommandFactory.h"


class StackCommandFactory : public CommandFactory
{
public:



    virtual Subtract * createSubtractionCommand(void);
    virtual Add * createAdditionCommand(void);
    virtual Divide * createDivisionCommand(void);
    virtual Multiply * createMultiplyCommand(void);
    virtual Modulus * createModulusCommand(void);
    virtual Negation * createNegationCommand(void);

protected:
    Subtract * sub;
    Add * add;
    Divide * div;
    Multiply * mul;
    Modulus * mod;
    Negation * neg;

};

#endif   // !defined _STACKCOMMANDFACTORY_H_

//StackCommandFactory.cpp
#include "StackCommandFactory.h"

Subtract * StackCommandFactory::createSubtractionCommand(void)
{
    return sub;
}

Add * StackCommandFactory::createAdditionCommand(void)
{
    return add;
}

Divide * StackCommandFactory::createDivisionCommand(void)
{
    return div;
}

Multiply * StackCommandFactory::createMultiplyCommand(void)
{
    return mul;
}

Modulus * StackCommandFactory::createModulusCommand(void)
{
    return mod;
}

Negation * StackCommandFactory::createNegationCommand(void)
{
    return neg;
}

回答1:

There's a few issues with your code. Mostly centring about the use of member functions rather than global functions. You try to get the member functions from an object, where you should be getting them from the class itself. ( i.e. instead of &fact.createAdditionCommand you need &CommandFactory::createAdditionCommand.) But this results in an unbound member function, which means you need to call it using (fact.*fn)() - i.e. with an object of the CommandFactory class. This is not ideal - and not what you're looking for. You are looking for a bound member function. Using these in non C++-11 applications is possible, but ugly. You can use boost libraries to really help with that (and the code below will pretty much work unchanged other than some std to boost style changes.) If you're using C++-11 then you can use the C++-11 function objects.

Here's a complete example derived from your source:

#include <vector>
#include <map>
#include <functional>
#include <string>

struct Command {};
struct Subtract : Command {};
struct Add : Command {};

class CommandFactory
{
  public:

    virtual Subtract * createSubtractionCommand() = 0;
    virtual Add * createAdditionCommand() = 0;
};

class StackCommandFactory : public CommandFactory
{
  public:

    virtual Subtract * createSubtractionCommand(void);
    virtual Add * createAdditionCommand(void);

    Subtract * sub;
    Add * add;
};

Subtract * StackCommandFactory::createSubtractionCommand(void) { return sub; }
Add * StackCommandFactory::createAdditionCommand(void) { return add; }

class Parser
{
  public:
    Parser (CommandFactory & fact);

    std::map<std::string, std::function<Command*()> > operations; 
};

Parser::Parser(CommandFactory & fact)
{
  operations["+"] = std::bind(&CommandFactory::createAdditionCommand, &fact);
  operations["-"] = std::bind(&CommandFactory::createSubtractionCommand, &fact);
}

#include <iostream>
int main()
{
  Add add;
  Subtract sub;

  StackCommandFactory command_factory;
  command_factory.add = &add;
  command_factory.sub= &sub;
  Parser parser(command_factory);

  std::cout<<"&add = "<<&add<<std::endl;
  std::cout<<"Add = " <<  parser.operations["+"]() <<std::endl;
  std::cout<<"&sub = "<<&sub<<std::endl;
  std::cout<<"Sub = " <<  parser.operations["-"]() <<std::endl;

  return 0;
}

I get the output

&add = 0x7fff58d538d8
Add = 0x7fff58d538d8
&sub = 0x7fff58d538d0
Sub = 0x7fff58d538d0

Showing that the Add object returned by going through the parser is the same as that stored into the CommandFactory. (And same for the Subtract object)



回答2:

You can't do it in standard C++. For reasons have a look here & here.

EDIT: Instead of storing "Command * (*)()" into operations, why not change "operations" value type to store "Command *" ? Or perhaps have a relook into the low-level design?



回答3:

sorry try

operations["*"] = fact.createMultiplyCommand;

or

operations["*"] = fact->createMultiplyCommand;