0

在这里,我找到了这段代码(并且我对其进行了一些修改):

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

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

Eval<float>(sin)

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

4

6 回答 6

3

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

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

Eval显然期望它的参数是一个可调用类型:一个函数、一个指向函数的指针或一个定义operator(). 因此,您不能将模板参数指定为double. 如果有的话,它应该是double(double)= 函数接受一个双精度并返回一个双精度。但是,大多数情况下,您根本不必指定模板参数:它将根据您传入的实际参数推导出来。像这样:

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

void someFun()
{
  Eval(myFun);
  Eval([](double a){ global_var = a; });
}
于 2013-03-14T09:25:17.030 回答
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 的函数特征来概括这一点

那么,是不是应该这样调用呢?

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

Eval(sin);

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

Eval<float(float)>(sin);

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

我们没有。那是参考,不是指针。

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

不,它是对 的引用const,所以我们无法更改它。

如果不是,为什么我们需要 & 符号?

有些类型的复制成本很高;别人根本无法复制;但所有类型都可以通过引用传递。所以一个完全通用的函数模板需要通过引用来获取它的参数,以便对所有类型都可用。

于 2013-03-14T09:23:29.853 回答
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);
}

现场示例

于 2013-03-14T09:19:37.790 回答
0

如果你想返回值,你会想使用这样的东西

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

笔记

  1. 按值传递函数更为惯用。
  2. 这可能不适用于void返回类型。
  3. 该功能必须具有适应性
  4. 您不需要传递模板参数,因为编译器可以自己解决。
于 2013-03-14T09:22:49.403 回答
0

据我了解, Eval 函数将另一个函数作为参数并返回其值

不,Eval返回无效。f(3.14)不使用任何回报。

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

在大多数情况下Eval(obj)就足够了,并且类型F将从obj. 如果这是模棱两可的,您将需要明确:( Eval<float(float)>(sin)我希望您包含了正确的头文件)。任何可以用double参数“调用”的类型的“对象”都将编译。

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

不在这里const&意思是 const 参考。你直接接受这个论点,但保证不会改变它。

于 2013-03-14T09:36:51.077 回答
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 引用传递?有几个原因:

  • 不复制传递的对象,提高性能;
  • 您不能传递不存在的对象(引用不能为空)
  • const 引用中的 const 确保对象本身不会在函数调用中更改
于 2013-03-14T09:20:36.013 回答