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

Convert exception to optional: cant resolve overloaded function type

本文关键字:解决 重载 函数 类型 转换 异常      更新时间:2023-10-16

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

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. 如何使其适用于过载?

提前谢谢。

这里的问题在于模板类型推断,并且是完美的转发失败之一。当你有一个重载函数时,应该推断出其中哪一个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);

我的get_opt函数格式是否正确? 参数的通用参考和使用std::forward是这种情况的必经之路吗?

是的。

为什么编译器看不到要调用的重载,因为参数 int 已传递,他应该正确计算出正确的重载?

编译器不会检查函数调用以查看应选择哪个重载。事实是,当您有一个重载函数时,仅按其名称引用该函数会导致歧义,因为它可能有多个函数。它实际上是一种"未解析的重载函数类型"。

您通常可以通过转换为正确的类型来解决此问题,但是如果您的函数使用模板参数推导,您将无法在 get_opt 中的调用站点实现这一点。您可以使用 lambda 表达式来解决这个问题:

auto glambda = [&] (auto&& x) { return std::to_string(x); });
auto n = get_opt(glambda, 1234);