1

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;
}
merlin2011
  • 71,677
  • 44
  • 195
  • 329
thed0ctor
  • 1,350
  • 4
  • 17
  • 34

3 Answers3

0

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?

Community
  • 1
  • 1
Arun
  • 2,087
  • 2
  • 20
  • 33
0

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)

Michael Anderson
  • 70,661
  • 7
  • 134
  • 187
  • Before C++11 I'd use `boost::function` instead. If thats not an option, you can build something similar using functor objects instead to wrap the bound member functions. – Michael Anderson Mar 21 '13 at 02:47
  • I'm not fully understanding the code that you've written. probably because I'm not sure what you mean by bounded and unbounded functions. Are there any stackoverflow posts/articles you recommend I read about this? – thed0ctor Mar 21 '13 at 16:37
  • 1
    Here's the details on std::bind, http://en.cppreference.com/w/cpp/utility/functional/bind and a nice SO answer about boost::bind and boost::function is here: http://stackoverflow.com/questions/527413/how-boostfunction-and-boostbind-work#527983 – Michael Anderson Mar 22 '13 at 01:40
  • Hey I'm trying to use functor objects to bound the member functions as you said (since I can't use boost or c++11) but am having some issues. I posted the question here: http://stackoverflow.com/questions/15733390/cant-initialize-functor-objects-when-passing-derived-class-in-c/15735616?noredirect=1#15735616. Any help would be appreciated. Thanks again – thed0ctor Apr 01 '13 at 13:08
-1

sorry try

operations["*"] = fact.createMultiplyCommand;

or

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

andrew.butkus
  • 777
  • 6
  • 19
  • that gives me more errors. It then says that the function is missing the list of arguments (error C3867) – thed0ctor Mar 20 '13 at 01:13
  • ok im looking at Command * (CommandFactory::*)() does fact.createMultiplyCommand return a Command ptr? some of the implementation detail is missing, operations["*"] = &(fact.createMultiplyCommand()); normally i use boost::bind to do this type of thing – andrew.butkus Mar 20 '13 at 01:19
  • http://stackoverflow.com/questions/2304203/how-to-use-boost-bind-with-a-member-function an example of how easy it is with boost bind ... – andrew.butkus Mar 20 '13 at 01:22
  • unfortunately this is a class project so I can't use `boost`. However yes, `fact.createMultiplyCommand()` returns a `Command` pointer. When I change that statement from `std::map operations;` to `std::map operations;` it removes some errors later down the error list. – thed0ctor Mar 20 '13 at 01:22
  • can you provide the definition for fact.createMultiplyCommand – andrew.butkus Mar 20 '13 at 01:28
  • I've provided the implementations. The mapping must be from `fact` because `fact` is a specific implementation of CommandFactory. CommandFactory is just an interface, it has no implementation of the methods. I also changed the implementation a little: `std::map operations;` to `std::map operations;` because the former caused more errors. – thed0ctor Mar 20 '13 at 01:46