3

这个问题源于我在这里问过的一个问题。我不能使用任何外部库或 C++ 11 规范。这意味着我不能使用 std::bind、std::function、boost::bind、boost::function 等。我必须自己编写。问题如下:

考虑代码:

编辑

这是一个完整的程序,可按要求显示问题:

#include <map>
#include <iostream>


class Command {    
public:
    virtual void executeCommand() = 0;
};

class Functor {
public:
    virtual Command * operator()()=0; 
};

template <class T> class Function : public Functor {
private:
    Command * (T::*fptr); 
    T* obj;                  
public:
    Function(T* obj, Command * (T::*fptr)()):obj(obj),
        fptr(fptr) {}

    virtual Command * operator()(){
        (*obj.*fptr)();   
    }            
};

class Addition:public Command {
public:
    virtual void executeCommand(){
        int x;
        int y;
        x + y;
    }
};

class CommandFactory {
public:
    virtual Addition * createAdditionCommand() = 0;
};

class StackCommandFactory: public CommandFactory {
private:
    Addition * add;
public:
    StackCommandFactory():add(new Addition()) {}

    virtual Addition * createAdditionCommand(){
         return add;
    }
};

void Foo(CommandFactory & fact) {
    Function<CommandFactory> bar(&fact,&CommandFactory::createAdditionCommand);
}

int main() {
    StackCommandFactory fact;
    Foo(fact);
    return 0;
}

它给出的错误是"no instance of constructor "Function<T>::Function [with T=CommandFactory] matches the argument list, argument types are: (CommandFactory *, Addition * (CommandFactory::*)())

我认为它在抱怨,因为我将它传递给派生类型。我必须使用对抽象类的指针/引用,因为fact以后可能不是 StackCommandFactory。

我不能说:

void Foo(CommandFactory & fact){
      Function<CommandFactory> spf(&fact,&fact.createAdditionCommand); //error C2276

}

因为那时我收到错误 C2276 说(在我链接到的问题中)'&' : illegal operation on bound member function expression.

所以明确我的问题是:“我如何初始化这个函子对象,以便我可以将它与上述接口一起使用?”

4

3 回答 3

1

您需要对 bar 实例的第二个参数进行显式转换:

Function<CommandFactory> bar(&fact,
  reinterpretet_cast<Command *(CommandFactory::*)()>(&CommandFactory::createAdditionCommand));

此外,您缺少以下方法指针属性的括号Function

Command * (T::*fptr)();

此错误可能会阻止您找到上述解决方案。

您还缺少那里的return关键字operator()(由于我的函数式编程习惯,我经常犯这个错误):

virtual Command * operator()(){
   return  (obj->*fptr)();
}            

您可以通过使返回类型成为模板参数来避免强制转换:

template <class T, typename D> 
class Function : public Functor {
private:
    D * (T::*fptr); 
    T* obj;
public:
    Function(T* obj, D * (T::*fptr)()): obj(obj),  fptr(fptr){}
    virtual Command * operator()(){
        return (obj->*fptr)();
    }            
};

void Foo(CommandFactory & fact){
    Function<CommandFactory, Addition> bar(&fact, &CommandFactory::createAdditionCommand);
}

请注意,我毕竟没有模板化Functor。虽然起初对我来说这似乎是一个好主意,但它使事情变得更加复杂。如果您也想制作Functor模板,则返回类型必须完全相同,您不能在它们之间使用继承关系,除非您将它们都设为Function模板的参数。根据经验,每当你偶然发现这样的模板问题时,请记住,模板的核心就像 C 宏,它是一种重写机制,它将模板分别扩展为真正的 C++ 类型(函数或类)。你可以这样描述问题:

template <typename T, typename D>
class Function : public Functor<D> { /* ... */ };

将扩大到

class Function<CommandFactory, Addition> : public Functor<Addition> {
    /* ... */
};

Functor<Addition> 并且Functor<Command>根本没有任何关系;这是两个不同的类别。

如果 C++ 模板确实带有有界多态性的概念(如在 Java 或 C# 中),那么它可能可以以接近您的意图的方式编写它。

我建议:

  • 保持Functor一个简单的类,暂时使代码更易于使用,并且
  • 如果以后需要,尝试使用该新功能重构一个工作版本。
于 2013-03-31T19:37:52.573 回答
1

这是对我原始答案的修改,似乎可以满足您的需要,而无需使用 C++11 或 boost 中的任何仿函数。

#include <vector>
#include <map>
#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 CommandGetterImpl
{
  public:
    virtual CommandGetterImpl* clone() const=0;
    virtual Command* get()=0;
    virtual ~CommandGetterImpl() {};
};

class CommandGetter
{
  public:
  Command* get() { return impl_->get(); }
  ~CommandGetter() { delete impl_; }
  CommandGetter( const CommandGetter & other ) : impl_(other.impl_?other.impl_->clone():NULL) {}
  CommandGetter& operator=( const CommandGetter & other ) {
     if (&other!=this) impl_= other.impl_?other.impl_->clone():NULL;
     return *this;
  }
  CommandGetter() : impl_(NULL) {}
  CommandGetter( CommandGetterImpl * impl ) : impl_(impl) {}
  CommandGetterImpl * impl_;
};

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

    std::map<std::string, CommandGetter > operations; 
};

template<typename MEMFN, typename OBJ >
class MemFnCommandGetterImpl : public CommandGetterImpl
{
  public:
  MemFnCommandGetterImpl(MEMFN memfn, OBJ *obj) : memfn_(memfn), obj_(obj) {}
  MemFnCommandGetterImpl* clone() const { return new MemFnCommandGetterImpl( memfn_, obj_) ; }
  Command* get() { return (obj_->*memfn_)(); }
  MEMFN memfn_;
  OBJ * obj_;
};


template< typename MEMFN, typename OBJ >
CommandGetter my_bind( MEMFN memfn, OBJ * obj )
{
  return CommandGetter( new MemFnCommandGetterImpl<MEMFN,OBJ>(memfn,obj) );
};

Parser::Parser(CommandFactory & fact)
{
  operations["+"] = my_bind(&CommandFactory::createAdditionCommand, &fact);
  operations["-"] = my_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["+"].get() <<std::endl;
  std::cout<<"&sub = "<<&sub<<std::endl;
  std::cout<<"Sub = " <<  parser.operations["-"].get() <<std::endl;

  return 0;
}
于 2013-04-02T01:33:59.403 回答
-3

一般来说,使用成员函数指针而不是std::function. 更普遍,

typedef std::function<void()> Command;
typedef std::function<Command()> Functor;

实际上,您的代码中绝对不需要任何成员函数指针。

于 2013-03-31T23:09:39.723 回答