如何将函数指针和函数对象包装在通用代码中?

mas*_*tis 1 c++ templates function-pointers functor c++11

以下模板定义

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;
};
Run Code Online (Sandbox Code Playgroud)

使用以下测试代码实例化时,使用gcc 4.7.3(错误:字段'Command :: 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);
}
Run Code Online (Sandbox Code Playgroud)

如果我将没有address-of运算符的TestFunction传递给testCommand构造函数,也会出现错误消息,但如果我传递一个显式命名的函数指针或使用address-of运算符传递参数,则会消失.我认为这段代码应该适用于Modern C++ Design的第5章.

无法存储函数引用的原因是什么,但函数指针工作正常?是否有任何变通方法可以在不失去支持的情况下编译,同时也可以将函数作为参数传递给Command的构造函数?

seh*_*ehe 5

更改一行可以修复它:

Command<void(*)(int, double), void, int, double> testCommand(fRef);
Run Code Online (Sandbox Code Playgroud)

不同的是,您现在传递的是函数指针,而不是函数类型.(函数不可复制,但指针是).

传递时,引用fRef 会衰减为函数指针.

我不建议使用std::function性能是否重要.

在Coliru上看到它

请注意,只需稍加重写,您就可以更好地完成所有工作:

int main()
{
    auto command = make_command(testFunction);
    command(1, 3.14);
}
Run Code Online (Sandbox Code Playgroud)

为此,我建议将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...); }
};
Run Code Online (Sandbox Code Playgroud)

现在,您可以Func通过具有工厂函数对模板参数进行类型推导:

template <typename Func> Command<Func> make_command(Func f)
{
    return Command<Func>(f);
}
Run Code Online (Sandbox Code Playgroud)

在Coliru也可以看到这种方法.当然,输出它一样:

TestFunctor::operator()(1, 3.14) called.
Run Code Online (Sandbox Code Playgroud)