我正在尝试构建一个将异常转换为可选的泛型函数:
template<typename Func, typename... Args>
auto get_opt(Func f, Args&&... args)
{
auto ret = std::experimental::optional<decltype(f(std::forward<Args>(args)...))>();
try
{
ret = f(std::forward<Args>(args)...);
}
catch(const std::exception&)
{}
return ret;
}
然后我可以将它与任何可能引发异常的函数一起使用,并且对于没有重载的函数它可以正常工作:
int test(const std::string& s)
{
return std::stoi(s);
}
int main(int argc, char** argv)
{
auto n = get_opt(test, "1234");
if(n)
{
std::cout << "value: " << *n << std::endl;
}
}
问题是如果我使用一个有重载的函数,编译器会抱怨他不知道调用什么重载:
auto n = get_opt(std::to_string, 1234);
main.cpp:25: error: no matching function for call to 'get_opt(<unresolved overloaded function type>, int)'
这个应该调用std::to_string(int)
重载。
我的get_opt
功能是否良好形成?是args
的通用参考,并使用std::forward
的方式来解决此问题?
为什么编译器看不到调用哪个重载,因为参数int
已经通过,他应该正确计算正确的重载?
如何让它适用于重载?
提前感谢。
答案 0 :(得分:2)
这里的问题是模板类型推导,并且是完美的转发失败之一。当你有一个重载函数时,应该推导出哪一个Func
?
有两种解决方法。或者,创建一个正确类型的函数指针并将其传入,或者只将to_string
强制转换为该类型:
using FuncType = std::string(*)(int );
FuncType f = std::to_string;
auto n = get_opt(f, 1234);
auto n2 = get_opt(static_cast<FuncType>(std::to_string), 1234);
答案 1 :(得分:1)
我的
get_opt
功能是否良好形成?是args的通用参考,并使用std::forward
的方式来解决这个问题吗?
是
为什么编译器看不到调用了什么重载,只要传递了参数int,他应该正确计算正确的重载?
编译器不会检查函数调用以查看应选择哪个重载。事实是,当你有一个重载函数时,仅仅通过它的名称来引用该函数会导致模糊,因为它可能有多个函数。它实际上是一个“未解决的重载函数类型”。
你通常可以通过转换为正确的类型来解决这个问题,但是如果你的函数使用模板参数推导,你将无法在get_opt
内的调用站点实现这一点。你可以用lambda表达式解决这个问题:
auto glambda = [&] (auto&& x) { return std::to_string(x); });
auto n = get_opt(glambda, 1234);