【问题标题】:function objects for class methods类方法的函数对象
【发布时间】:2019-05-20 09:21:58
【问题描述】:

当函数不是方法时,我知道如何将函数作为输入参数,但当函数方法时,我不知道该怎么做。

这是我尝试过的:

#include <iostream>

class A
{
    void funct_1(int a, void (A::*f)(int))
    {
        (A::*f)(a);
    }

public:

    void funct_2(int k)
    {
        // do something
    }

    void funct_3(int k)
    {
        // do something
    }

    void funct_4(int k)
    {
        // some reason to use the function argument functionality...
        if (k % 2)
            funct_1(k, funct_2);
        else
            funct_1(k, funct_3);
    }
};

int main()
{

    A a;

    a.funct_4(4);

    return 0;
}

以上代码无法编译。我尝试了很多变体,但找不到任何有效的语法用法。 有人可以根据语法解释我在这里做错了什么吗?

【问题讨论】:

    标签: c++ class function-object


    【解决方案1】:

    指向成员语法的指针总是很难弄清楚。你一直都在,只要把第一个成员函数改成

    void funct_1(int a, void (A::*f)(int))
    {
        (this->*f)(a);
    }
    

    第四个到

    void funct_4(int k)
    {
        if (k % 2)
            funct_1(k, &A::funct_2);
        else
            funct_1(k, &A::funct_3);
    }
    

    如果您最初尝试调用成员函数,请注意(A::*f)(a); 在概念上是错误的,因为它没有将成员函数指针fA实例 相关联。成员函数指针是类定义的偏移量,但不严格到该类的特定实例。这必须在进行实际调用时提供。存在特定的运算符来做到这一点,即.*-&gt;*,如this-&gt;*f。由于它们的优先级较低,您需要添加一组额外的括号:(this-&gt;*f)

    【讨论】:

    • 谢谢!那行得通。我很快就会接受答案(显然 stackoverflow 阻止我在前 10 分钟内接受答案!)
    • 请注意,这可能会导致意外行为,OP 也应将A 的实例作为参数传递。
    • @Timo A 实例不是this 是否合理?我认为 OP 不想考虑这种情况,但我可能错了。
    • Idk 也可以,但一旦他在其中一个调用函数中使用A 的第二个实例,他可能会遇到麻烦。
    • @Timo 我明白了。但是当指向成员的指针在类本身中传递时,隐含地假设 this 是调用指针时使用的实例对我来说似乎很好。但我同意将指向成员的指针视为应该与实际实例一起传递的东西通常是个好主意。
    【解决方案2】:

    我不知道你是否需要使用精确的签名,但你不能这样做吗?

    template<typename Func>
    void funct_1(int a, Func&& func)
    {
       std::forward<Func>(func)(a);
    }
    

    您的方法的签名不会改变:

    void funct_4(int k)
    {
        // some reason to use the function argument functionality...
        if (k % 2)
            funct_1(k, funct_2);
        else
            funct_1(k, funct_3);
    }
    

    你甚至可以为任意数量的参数扩展它

    template<typename Func>
    void funct_1(Func&& func, Args&&... args)
    {
       std::forward<Func>(func)(std::forward<Args>(args)...);
    }
    

    那些允许使用函数作为参数。如果您打算按照您所展示的方式在您的班级中使用它,这主要是一个设计缺陷,请重新考虑班级结构。

    如果你想在你的类中传递成员函数,请将它包含在一个 lambda 和 std::function 中,这样你就可以将它用作变量并使用上面的方法。

    如果您只是想为您的示例提供一种干净的方式,那么实际上确实存在一种极其方式:

    void funct_1(int a, auto&& func)
    {
       (this->*func)(a);
    }
    

    所以你的样本变成了

    #include <iostream>
    #include <functional>
    
    class A
    {
        void funct_1(int a, auto&& func)
        {
           (this->*func)(a);
        }
        
    public:
        void funct_2(int k)
        {
            std::cout << "func 2" << std::endl;
        }
    
        void funct_3(int k)
        {
            std::cout << "func 3" << std::endl;
        }
    
        void funct_4(int k)
        {
            // some reason to use the function argument functionality...
            if (k % 2)
                funct_1(k, &A::funct_2);
            else
                funct_1(k, &A::funct_3);
        }
    };
    
    int main()
    {
        A a;
        a.funct_4(4);
    
        return 0;
    }
    

    Live demo

    【讨论】:

    • 为什么是std::forward&lt;Func&gt;
    • 是的,但你为什么要转发可调用对象?
    • @Elliott Smith 模板避免了痛苦的指针语法,让您更加灵活。如果在某个时刻想要接受不同的签名(无论是返回还是输入类型?)
    • @Elliott 正如您在一年后所说的那样,如果至少启用了 C++14,确实存在一种更简洁的表达方式。您将在编辑后的答案中找到它
    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 2019-06-10
    • 2017-03-13
    • 2018-02-07
    • 2012-07-23
    • 2016-01-22
    • 2015-03-05
    • 1970-01-01
    相关资源
    最近更新 更多