以下模板定义
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(错误:字段'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);
}
如果我将没有address-of运算符的TestFunction传递给testCommand构造函数,也会出现错误消息,但如果我传递一个显式命名的函数指针或使用address-of运算符传递参数,则会消失。我认为这段代码应该适用于现代C ++设计的第5章。
无法存储函数引用的原因是什么,但函数指针工作正常?是否有任何变通方法可以在不失去对作为Command的构造函数的参数传递函子的支持的情况下进行编译?
答案 0 :(得分:5)
更改一行可以修复它:
Command<void(*)(int, double), void, int, double> testCommand(fRef);
不同之处在于,您现在传递的是函数指针,而不是函数类型。 (函数不可复制,但指针是。)
传递时,引用fRef
将衰减到函数指针。
如果性能很重要,我建议不要使用std::function
。
请注意,只需稍加重写,您就可以更好地完成所有工作:
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
模板参数进行类型推导:
template <typename Func> Command<Func> make_command(Func f)
{
return Command<Func>(f);
}
也请参阅此方法 live on Coliru 。当然,输出也一样:
TestFunctor::operator()(1, 3.14) called.
答案 1 :(得分:2)
C ++ 11提供std::function
模板。你不必乱用函数指针。
您可以通过引用传递它们,复制它们,移动它们甚至可以用来存储lambdas:
std::function<void()> func = []() { std::cout << "Hi" << std::endl; };