C++ 如何使用std::log作为函数?

C++ 如何使用std::log作为函数?,c++,functional-programming,c++11,logging,C++,Functional Programming,C++11,Logging,我试图将std::log作为函数参数传递,但似乎存在std::log的重载实现,编译器无法解决它。代码: #include <cmath> #include <iostream> #include <vector> #include <string> #include <functional> template <typename FOper> double Eval(FOper fOper, double X) {

我试图将std::log作为函数参数传递,但似乎存在std::log的重载实现,编译器无法解决它。代码:

#include <cmath>
#include <iostream>
#include <vector>
#include <string>
#include <functional>

template <typename FOper>
double Eval(FOper fOper, double X)
{
    return fOper(X);
}

int main(int argc, char* argv[])
{
    std::function<double(double)> fPlus1 = std::bind(std::plus<double>(), 1.0, std::placeholders::_1);
    std::cout<<Eval(fPlus1, 10.0)<<std::endl;
    //  how to write this fLog ?
    //std::function<double(double)> fLog = std::log;
    //std::function<double(double)> fLog = std::log<double>;
    std::cout<<Eval(fLog, 10.0)<<std::endl;
    return 0;
}
如果我取消注释fLog定义的任一行,编译器将提示错误消息:

error: conversion from '<unresolved overloaded function type>' to non-scalar type 'std::function<double(doubl
e)>' requested
您可以这样做:

typedef double (*logtype)(double);
std::function<double(double)> fLog = (logtype) std::log;
强制转换将帮助编译器选择正确的重载

您也可以这样写:

double (*fLog )(double) =  std::log; //i.e don't use std::function

std::cout<<Eval(fLog, 10.0)<<std::endl;
您可以这样做:

typedef double (*logtype)(double);
std::function<double(double)> fLog = (logtype) std::log;
强制转换将帮助编译器选择正确的重载

您也可以这样写:

double (*fLog )(double) =  std::log; //i.e don't use std::function

std::cout<<Eval(fLog, 10.0)<<std::endl;

最简单的方法是简单地施放它:

typedef double (*log_d)(double);
std::function<double(double)> fLog = static_cast<log_d>(std::log);

通过强制转换,您可以为编译器提供一个使用重载函数的上下文,从而从中获得正确的函数指针。

最简单的方法是简单地强制转换它:

typedef double (*log_d)(double);
std::function<double(double)> fLog = static_cast<log_d>(std::log);

通过强制转换,您可以为编译器提供一个使用重载函数的上下文,这样就可以从中获得正确的函数指针。

问题在于,类似这样的内容本身没有任何意义:

std::bind std::log,_1;//无法解决。绑定什么功能?什么会被通过

日志不是模板,因此无法在其中调用std::log

不过,您可以创建自己的模板,这将求助于日志:

template< typename T >
T logT( T t )
{
   return std::log( t );
}
现在您可以在代码中使用logT

std::bind logT,1//应该可以工作


当然,如果需要,可以将fLog设置为指向logT的函数指针。使用C++11,您可以使用auto等,而不必手动键入其类型。

问题是,类似这样的内容本身没有任何意义:

std::bind std::log,_1;//无法解决。绑定什么功能?什么会被通过

日志不是模板,因此无法在其中调用std::log

不过,您可以创建自己的模板,这将求助于日志:

template< typename T >
T logT( T t )
{
   return std::log( t );
}
现在您可以在代码中使用logT

std::bind logT,1//应该可以工作


当然,如果需要,可以将fLog设置为指向logT的函数指针。使用C++11,您可以使用auto等,而不必手动键入其类型。

正如Xeo所解释的,即使使用显式转换重载函数,也可以使其工作。但是,由于您已经在使用std::function,这是C++11的一个特性,因此您最好使用lambda表达式作为初始值设定项:

function<double(double)> fLog = [](double x){return std::log(x);};
这在C++11中更可取,因为它避免了重载问题。此外,它比包装函数指针更有效,因为它节省了一级间接寻址,因此允许lambda的主体内联到内部包装器对象的函数调用操作符中

可能需要强调的是,在您的示例中使用std::function是不必要的,因为Eval已经是一个函数模板,并且类型参数FOper可以完全匹配函数对象的类型,而无需将其包装在std::function中。因此,如果您不需要使用std::function获得的类型擦除,您也可以编写

template <typename FOper>
double Eval(FOper fOper, double X)
{
    return fOper(X);
}

int main()
{
    auto flog = [](double x){return std::log(x);};
    std::cout << Eval(flog, 10.0) << std::endl;
}

正如Xeo所解释的,即使使用显式强制转换重载函数,也可以让它工作。但是,由于您已经在使用std::function,这是C++11的一个特性,因此您最好使用lambda表达式作为初始值设定项:

function<double(double)> fLog = [](double x){return std::log(x);};
这在C++11中更可取,因为它避免了重载问题。此外,它比包装函数指针更有效,因为它节省了一级间接寻址,因此允许lambda的主体内联到内部包装器对象的函数调用操作符中

可能需要强调的是,在您的示例中使用std::function是不必要的,因为Eval已经是一个函数模板,并且类型参数FOper可以完全匹配函数对象的类型,而无需将其包装在std::function中。因此,如果您不需要使用std::function获得的类型擦除,您也可以编写

template <typename FOper>
double Eval(FOper fOper, double X)
{
    return fOper(X);
}

int main()
{
    auto flog = [](double x){return std::log(x);};
    std::cout << Eval(flog, 10.0) << std::endl;
}

仅供参考:像_This和_This这样的名称是为实现保留的。您必须包装std::log。它是一个重载函数而不是模板,这一事实阻止您将std::log用作函子。类似于[]double x->{return std::logx;}的东西就足够了。对于@Xeo:I已经更改了命名样式。仅供参考:像_This和u This这样的名称是为实现保留的。您必须包装std::log。它是一个重载函数而不是模板,这一事实阻止您将std::log用作函子。类似于[]double x->{return std::logx;}的东西就足够了。对于@Xeo:我已经更改了命名样式。很好的样式!但编译器通常可以对传入算法的函数指针执行常量值优化,std::function的简单实现总是使用间接调用,因为该类的复杂性可能需要虚拟分派,然后才能决定是否需要遵循lambda或函数指针。@Potatoswatter:当然,std::function有一些间接级别,我认为这是无法避免的。据我所知,使用函数指针将
dd另一个级别,而lambda的函数调用操作符可以内联到std::函数的内部包装器的最后一个级别。但我不知道实际运行时的区别是什么。我想lambda版本更好-至少在std::log是编译器固有的情况下。难道你不能使用auto-fLog来避免std::function的间接级别吗?@Kleist:是的,既然OP无论如何都在使用模板,他也可以直接传递它或函数指针,但可能问题中的代码只是一个示例,OP实际上需要存储函数,在这种情况下std::function是有意义的。@Kleist:当然。但我认为首先使用std::function是有原因的。但你是对的。在Eval函数模板的上下文中,应该提到std::function在这种情况下是不必要的。我会在答案上加上这一点…好风格!但编译器通常可以对传入算法的函数指针执行常量值优化,std::function的简单实现总是使用间接调用,因为该类的复杂性可能需要虚拟分派,然后才能决定是否需要遵循lambda或函数指针。@Potatoswatter:当然,std::function有一些间接级别,我认为这是无法避免的。据我所知,使用函数指针将添加另一个级别,而lambda的函数调用操作符可以内联到std::function的内部包装器的最后一个级别。但我不知道实际运行时的区别是什么。我想lambda版本更好-至少在std::log是编译器固有的情况下。难道你不能使用auto-fLog来避免std::function的间接级别吗?@Kleist:是的,既然OP无论如何都在使用模板,他也可以直接传递它或函数指针,但可能问题中的代码只是一个示例,OP实际上需要存储函数,在这种情况下std::function是有意义的。@Kleist:当然。但我认为首先使用std::function是有原因的。但你是对的。在Eval函数模板的上下文中,应该提到std::function在这种情况下是不必要的。我会在答案中加上这一点。。。