2013-07-19 26 views
1

以下模板定义如何在泛型代码中包装函数指针和函数对象?

template <typename Func, typename ReturnType, typename... Arguments> 
class Command 
{ 
public: 
    Command(Func f) : m_func(f) { } 
    ReturnType operator()(Arguments... funcArgs) { return m_func(funcArgs...); } 
private: 
    Func m_func; 
}; 

给出一个错误信息的gcc 4.7.3(错误:字段“命令:: m_func”无效地被声明功能型)时用下面的测试代码实例化:

void testFunction(int i, double d) 
{ 
    std::cout << "TestFunctor::operator()(" << i << ", " << d << ") called." << std::endl; 
} 

int main() 
{ 
    void (&fRef)(int, double) = TestFunction; 
    Command<void(int, double), void, int, double> testCommand(fRef); 
} 

如果我将TestFunction没有address-of运算符传递到testCommand构造函数中,也会发生此错误消息,但如果传递了明确命名的函数指针或使用address-of运算符传递参数,则会消失。我的印象是这个代码应该在现代C++设计的第5章中有效。

背后的原因是不能存储对函数的引用,但函数指针工作正常吗?是否有任何解决方法可以在不失去支持将函子作为参数传递给Command构造函数的情况下进行编译?

回答

5

改变一条线可以修复它:

Command<void(*)(int, double), void, int, double> testCommand(fRef); 

所不同的是,你正在传递一个函数指针,而不是一个函数类型。 (函数不可复制,但指针是)。

参考fRef衰减当你通过它的函数指针。

如果性能重要,我不会建议使用std::function

看到它live on Coliru

注意一点点改写,你可以把它所有的工作好得多:

int main() 
{ 
    auto command = make_command(testFunction); 
    command(1, 3.14); 
} 

要做到这一点,我建议改变Command模板是:

template <typename Func> 
class Command 
{ 
    Func m_func; 
public: 
    Command(Func f) : m_func(f) { } 

    template <typename... A> auto operator()(A... args) const 
     -> decltype(m_func(args...)) 
    { return m_func(args...); } 
}; 

而现在,您可以在Func模板pa上进行类型扣除由具有工厂函数rameter:

template <typename Func> Command<Func> make_command(Func f) 
{ 
    return Command<Func>(f); 
} 

见这种方法live on Coliru了。当然,它的输出相同:

TestFunctor::operator()(1, 3.14) called. 
2

C++ 11提供了std::function模板。你不必弄乱函数指针。

可以把它们作为参考,将它们复制,移动他们,他们甚至可以用来存储lambda表达式:

std::function<void()> func = []() { std::cout << "Hi" << std::endl; };