将异常转换为可选:无法解析重载的函数类型

时间:2014-12-29 18:11:35

标签: c++ templates boost

我正在尝试构建一个将异常转换为可选的泛型函数:

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)重载。

  1. 我的get_opt功能是否良好形成?是args的通用参考,并使用std::forward的方式来解决此问题?

  2. 为什么编译器看不到调用哪个重载,因为参数int已经通过,他应该正确计算正确的重载?

  3. 如何让它适用于重载?

  4. 提前感谢。

2 个答案:

答案 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);