应该返回一个函数的类型和它的类型作为参数是一样的吗?

时间:2013-03-14 09:15:46

标签: c++ lambda pass-by-reference

Here我找到了这部分代码(我稍微修改了一下):

template<typename F>     
void Eval( const F& f ) {
     f(3.14);
}

据我所知,Eval函数将另一个函数作为参数,并为其参数的特定值返回其值(在上述情况下为3.14)。但我不确定应该使用什么作为函数的类型?它的返回类型?那么,是否应该按以下方式调用?:

Eval<float>(sin)

此外,为什么我们使用指针(&amp; -symbol)?我们是否通过参考传递参数,因为我们想改变它?我们是否要在Eval函数内重新定义函数?如果是的话,为什么我们不这样做呢?如果没有,为什么我们这样做,我们需要&amp;符号

6 个答案:

答案 0 :(得分:3)

Eval是一个功能模板。从此模板实例化的函数具有返回类型void,这意味着它不返回值。它只是在内部调用f(3.14)然后返回调用者。

其参数类型为类型F的常量引用,其中F是模板参数。通过const-reference传递意味着你不能修改函数内部的对象,但没有复制。函数f内部只是对象(或函数)的不同名称传入。

Eval显然希望它的参数是一个可调用类型:一个函数,一个指向函数的指针或一个定义operator()的类的对象。因此,您无法将模板参数指定为double。如果有的话,它应该是double(double) =函数取一个double并返回一个double。但是,大多数情况下,您根本不必指定模板参数:它将从您传入的实际参数中推断出来。就像这样:

void myFun(double x)
{
  std::cout << x << '\n';
}

void someFun()
{
  Eval(myFun);
  Eval([](double a){ global_var = a; });
}

答案 1 :(得分:2)

  

但我不确定应该使用什么作为函数的类型?

函数类型看起来像float(float)

或者你的意思是回归类型?在现代C ++中,您可以推断出返回类型:

template <typename F>
auto Eval(const F & f) -> decltype(f(3.14)) {
    return f(3.14);
}

如果你坚持使用旧版本的语言,那就相当棘手了。您可以为普通函数以及包含result_type定义的函数类型(例如从std::unary_function派生的函数类型)提供重载:

template <typename Ret, typename Arg>
Ret eval(Ret (&f)(Arg)) {return f(3.14);}

template <typename F>
typename F::result_type eval(F const & f) {return f(3.14);}

可能通过定义特征类或使用Boost's function traits

来概括这一点
  

那么,是否应该按以下方式调用?

如果只有一个具有该名称的函数,则可以使用依赖于参数的查找:

Eval(sin);

但是,如果这是std::sin,那么有多个重载,因此您必须指定类型:

Eval<float(float)>(sin);
  

此外,为什么我们使用指针(&amp; -symbol)?

我们没有。这是一个参考,而不是一个指针。

  

我们是否通过引用传递参数,因为我们想要改变它?

没有。它是对const的引用,因此我们无法更改它。

  

如果没有,我们为什么要这样做&amp;符号

某些类型的复制费用昂贵;其他人根本无法复制;但所有类型都可以通过引用传递。因此,完全通用的函数模板需要通过引用获取其参数,以便可用于所有类型。

答案 2 :(得分:1)

你传递的是可调用类型,这意味着它是std::function<double(double)>或指向函数(double)(fooptr*)(double)或类/结构的函数指针其中doubule operator()(double)重载,以便可以像调用它一样调用它。

f()中有Eval的事实告诉您,传递给F的任何类型都应该使用()来调用

以下是您可以使用它的示例:

#include<iostream>

template<typename F>     
void Eval( const F& f ) {
    std::cout << f(3.14);
}

double foo(double d)
{
   return d + d;
}
int main()
{

 Eval(foo);
}

Live Example

答案 3 :(得分:0)

在C ++模板中,在编译过程中实例化,所以如果你传递任何支持调用的东西,它都会有效。

例如:

class MyClass
{
public:
    void operator() (double d)
    {
        // Do something
    } 
}

MyClass m;

Eval(m);

或者:

Eval([](double d) { /* ... */ });

或者:

void DoSth(double d)
{
    // ...
}

Eval(DoSth);

为什么我们传递const引用?有几个原因:

  • 不会复制传递的对象,这会提高性能;
  • 您无法传递不存在的对象(引用不能为null)
  • const引用中的
  • const确保在函数调用
  • 中不会更改对象本身

答案 4 :(得分:0)

如果您想要返回该值,您可能希望使用类似这样的内容

template<typename F>     
typename F::result_type Eval(F f) {
     return f(3.14);
}

注释

  1. 按值传递函数更为惯用。
  2. 这可能不适用于void返回类型。
  3. 该功能必须为adaptable
  4. 您无需传递模板参数,因为编译器可以自行完成。

答案 5 :(得分:0)

  

据我所知,Eval函数需要另外一个函数   参数并返回其值

不,Eval返回无效。无论使用何种f(3.14)返回。

  

但是我不确定应该使用什么作为函数的类型?它的   返回类型?那么,是否应该按以下方式调用?:   Eval<float>(sin)

在大多数情况下,Eval(obj)就足够了,F类型将从obj类型“推断”出来。如果是ambiguos,你需要明确:Eval<float(float)>(sin)(我已经包含了rigth头文件)。可以使用double参数“调用”的任何类型的“对象”都将编译。

Moreover, why do we use pointers (&-symbol)? 

没有。这里const&表示const引用。您可以直接访问参数,但保证不会更改它。