首页 > 解决方案 > 标准:任何抛出异常解析函数类型

问题描述

我在从 std::any 解析函数类型时遇到问题。

我基本上是在包装一个函数,它是 lambda 函数中的初始参数,稍后调用它来调用包装的函数,但使用一组新的参数。这就是包装函数的样子。

void Hello(std::string str)
{
    LOG(str);
}

我正在尝试像这样完成包装 lambda:我有一个 lambda 函数,它要么执行包装函数,和/或简单地返回包装函数。

template<typename FuncName, typename... FuncArgs>
bool MMM(std::string EventName, FuncName&& EventFunction, FuncArgs&&... Args) noexcept
{
     //Storing lambda here                
     auto fPtr = std::function<std::any(bool)>([=](bool x)
                                               {
                                                    if(x){
                                                            EventFunction(Args...);
                                                    }
                                                    return (FuncName)EventFunction;
                                                });
}

现在,当我尝试像这样调用这个 lamdba 时:

template<typename E, typename FuncName, typename... FuncArgs>
bool AAA(E EventName, FuncName &&EventFunction, FuncArgs&&... Args)
{
    try {
    //resolving lambda and invoking it here
            auto func = std::any_cast<decltype(EventFunction)>(fPtr)(false));
            func(Args...);
    } catch (...) {
             std::cout<<"Didn't invoke function: Mismatch argument type.\n";
    }
    return true;
}

我通过以下方式调用此函数:

MMM(e, Hello, "Hello Florida");
MMM(e, Hello, "Hello USA");

AAA(e, Hello, "Hello World");

问题:当调用函数 AAA 时,我收到一个异常,提示 auto_cast 无法解析函数类型。

在运行时,我看到 (fPtr)(false) 正在返回:

std::__1::function<std::__1::any (bool)>     Function = Hello(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) 

虽然似乎 decltype(EventFunction) 是类型

void (&)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) 0x0000000100012540

这似乎我几乎接近 std::any 存储在里面的东西,但仍然错过了一些我不明白的东西!如何解决此 std::any_cast 不匹配问题?

标签: c++c++17

解决方案


首先,如果您不需要使用提供的参数MMM并覆盖它们,这会隐藏一个错误,您将错误的参数发送到MMM. 我建议提供所需的东西,MMM以便它可以制作正确的参数集。


您的函数MMMAAA两者都通过转发引用接收函数。为了正确解析调用,它解析到void(&)(std::string)哪个是对函数的引用。

然后,在 lambda 中返回该函数:

return (FuncName)EventFunction;

这确实会转换回EventFunction函数引用,但是返回类型推导会衰减类型,所以它变得等价于:

[](bool) -> void(*)(std::string) { /* ... */ }

然后,你的其他函数做同样的事情。如果我们扩展模板,我们会得到如下所示的内容:

auto func = std::any_cast<void(&)(std::string)>(fPtr)(false));
func(Args...);

但是其中包含的类型std::any是指向函数的指针,而不是引用。


即使我们修复了返回类型,std::any也会衰减引用以使其成为函数指针。

解决方案是不通过转发引用接收函数,因为无论如何您都没有转发它:

template<typename E, typename FuncName, typename... FuncArgs>
bool MMM(E EventName, FuncName EventFunction, FuncArgs&&... Args) { /* ... */ }

template<typename E, typename FuncName, typename... FuncArgs>
bool AAA(E EventName, FuncName EventFunction, FuncArgs&&... Args) { /* ... */ }

推荐阅读