以下函数作为参数的函数有什么好处:
template<class Function> void test1(Function f);
template<class Function> void test2(Function& f);
template<class Function> void test3(const Function& f);
其中传递的函数可以是仿函数,std ::函数,函数指针或lambda函数。
答案 0 :(得分:6)
使用通用引用,您无需考虑它:
template<class Function> void test(Function&& f);
答案 1 :(得分:4)
当一个参数传递给一个推断参数类型的函数模板时,关于如何传递参数这是一个有趣的问题。值得注意的是,使用参数的确切性质无关紧要:参数是否用作函数对象,迭代器,值等与答案完全无关。有四种选择:
template <typename T> void f(T&& a)
template <typename T> void f(T& a)
template <typename T> void f(T const& a)
template <typename T> void f(T a)
关于函数模板实际执行的操作有点重要:如果所有f()
使用其参数a
将其转发到另一个函数,则需要通过通用引用。被调用函数将对拒绝不适当选项的细节进行排序。当然,虽然通常很有用,但转发功能有点无聊。
如果f()
实际上对该对象做了某些事情,我们通常可以立即丢弃其中两个选项:
T const&
也没有给我们带来太多好处:我们得到了一个对象的参考,这个对象的生命时间我们无法控制,我们既不能移动也不能复制/移动它们如果对象本身被修改,则通过非const
引用传递对象会很有用。这显然是函数契约的一个重要部分,也是一个强加的设计选择,不能被函数的客户端覆盖。
首选方法是按值获取参数。通常,这使得函数行为的定义更容易,并且实际上保持选择类型是否应遵循为用户开放的值或引用语义!仅仅因为某些东西通过值传递并不意味着感兴趣的对象也通过值传递。特别是对于函数对象的情况,标准C ++库甚至提供了一个通用适配器,它给出了一个值类型引用语义:std::ref()
。
当然,界面设计是微妙的,并且会出现保证每个选项的情况。但是,作为一般经验法则,我认为这很简单:
...当然,这些规则仅适用于推断出类型的函数模板的参数。