【问题标题】:How to pass method and call it with variable number of arguments如何传递方法并使用可变数量的参数调用它
【发布时间】:2020-12-22 09:23:39
【问题描述】:

我有 CallProtector 类,它应该调用具有可变数量参数的方法,这些参数应该通过互斥锁保护调用,但我不知道如何使用它们的参数传递对象的方法。这是我到目前为止所拥有的:

class CallProtector
{
public:

    template<typename F, typename ...Args>
    void callProtectedMethod(F& lambda, Args... args)
    {
        std::lock_guard<std::mutex> guard(m_guard);
        lambda(args);
    }

private:
    std::mutex m_guard;
};

我正在尝试这样使用它:

class Car
{
public:
    void updateEngine(int engineModelType) {}
};

int main()
{
    Car alfaRomeo;
    CallProtector callProtector;
    callProtector.callProtectedMethod(&Car::updateEngine, 10);

    return 0;
}

但我有编译错误提示

no instance of function template "CallProtector::callProtectedMethod" matches the argument list

感谢任何帮助,在此先感谢。

【问题讨论】:

    标签: c++ c++14 c++17 variadic-templates variadic-functions


    【解决方案1】:

    以下可能对您有用:

    class CallProtector
    {
    public:
    
        template<typename F, typename ...Args>
        void callProtectedMethod(F&& func, Args&&... args)
        {
            std::lock_guard<std::mutex> guard(m_guard);
            func(std::forward<Args>(args)...);
        }
    
    private:
        std::mutex m_guard;
    };
    

    然后像这样使用它:

    Car alfaRomeo;
    CallProtector callProtector;
    
    auto updateEngine = std::bind(&Car::updateEngine, &alfaRomeo, std::placeholders::_1); 
    callProtector.callProtectedMethod(updateEngine, 10);
    

    编辑

    或者这也可以:

    template<typename F, typename ...Args>
    void callProtectedMethod(F&& func, Args&&... args)
    {
        std::lock_guard<std::mutex> guard(m_guard);
        std::invoke(std::forward<F>(func), std::forward<Args>(args)...);
    }
    

    然后

    callProtector.callProtectedMethod(&Car::updateEngine, alfaRomeo, 10);
    

    【讨论】:

    • 它对我不起作用,说:“术语不评估为带 1 个参数的函数”。但我们不能只将所有参数转发给 std::invoke?这有什么理由吗?这应该很简单,但我真的想不通。
    • 什么term?我认为您没有向我们展示所有代码。它工作 here 这是 msvc
    • 谢谢,是的,我的错误是这段代码有效。但是我们可以避免绑定和转发所有参数吗?
    • 我用这段代码让它真正工作:std::invoke(std::forward(func), std::forward(args)...);
    【解决方案2】:

    从 C++17 开始,您可以使用std::invoke,只需将所有参数转发给它:

    template<typename ...Args>
    void callProtectedMethod(Args&&... args)
    {
        std::lock_guard<std::mutex> guard(m_guard);
        std::invoke(std::forward<Args>(args)...);
    }
    

    如果你想在 Car 实例上调用成员函数,你必须将指针传递给对象。

    Full demo

    【讨论】:

    • 谢谢,但它对我不起作用。编译错误说:“调用”没有找到匹配的重载函数。我正在使用带有 c++ 17 的 Visual Studio 2019。我们也可以使用 c++ 14 做同样的事情吗?
    • @Oleg 为什么不将callProtectedMethod 设为接受任何可调用对象的函数? Demo,传递的 callable 可以创建为闭包或 std::bind 函数的结果 - 传递参数没有问题,只需调用带有互斥锁保护的函数。
    • 我必须使用不同的对象并将指针传递给它。
    猜你喜欢
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多