我尝试将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
答案 0 :(得分:6)
最简单的方法是简单地投射它:
typedef double (*log_d)(double);
std::function<double(double)> fLog = static_cast<log_d>(std::log);
使用强制转换,您可以向编译器提供一个使用重载函数的上下文,因此将从中获取正确的函数指针。
答案 1 :(得分:3)
像Xeo解释的那样,即使使用显式强制转换重载函数,也可以使其工作。但是,既然你已经使用了std :: function(这是一个C ++ 11特性),你也可以使用lambda表达式作为初始化器:
function<double(double)> fLog = [](double x){return std::log(x);};
这在C ++ 11中是首选,因为它避免了重载问题。此外,它比包装函数指针更有效,因为它保存了一个间接级别,因此允许将lambda的主体内联到内部包装器对象的函数调用操作符中。
应该强调的是,在你的例子中使用std :: function是不必要的,因为Eval已经是一个函数模板,并且类型参数FOper可以完全匹配函数对象的类型而无需将其包装在std中::功能。所以,如果你不需要使用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;
}
答案 2 :(得分:1)
你这样做:
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;
答案 3 :(得分:0)
问题是这样的事情本身没有意义:
std::bind( std::log, _1 );
//无法解决。绑定什么功能? _1将被传递为什么?
日志不是模板,因此您无法在其中调用std::log<double>
。
您可以创建自己的模板,这将采用日志:
template< typename T >
T logT( T t )
{
return std::log( t );
}
现在您可以在代码中使用logT。
std::bind( logT<double>, _ 1 )
//应该有用。
如果需要,你当然可以使fLog成为指向logT的函数指针。使用C ++ 11,您可以使用auto等,而不必手动输入类型。