这个问题源自我之前提出的问题here。我不能使用任何外部库或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.
所以显然我的问题是:“如何初始化这个仿函数对象,以便我可以将它与上述接口一起使用?”
答案 0 :(得分:1)
您需要对条形图实例的第二个参数进行显式强制转换:
Function<CommandFactory> bar(&fact,
reinterpretet_cast<Command *(CommandFactory::*)()>(&CommandFactory::createAdditionCommand));
此外,您在Function
中缺少方法指针属性的parens:
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
设为模板,则返回类型必须完全相同,您不能使用它们之间的继承关系,除非您将它们作为template <typename T, typename D>
class Function : public Functor<D> { /* ... */ };
模板的两个参数。根据经验,每当你偶然发现这样的模板问题时,请记住该模板就像核心的C宏一样,它是一种重写机制,它将模板分别扩展为真正的C ++类型(函数或类)。您可以通过这种方式描述问题:
class Function<CommandFactory, Addition> : public Functor<Addition> {
/* ... */
};
将扩展为
Functor<Addition>
Functor<Command>
和Functor
根本没有任何关系;这是两个不同的类别。
如果C ++模板确实带有有界多态的概念(比如在Java或C#中),那么也许有可能以接近你的意图的方式编写它。
我建议:
答案 1 :(得分: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= ⊂
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;
}
答案 2 :(得分:-3)
一般来说,使用成员函数指针而不是std::function
是个坏主意。更一般地说,
typedef std::function<void()> Command;
typedef std::function<Command()> Functor;
实际上,对代码中的任何成员函数指针都没有任何需要。