【问题标题】:Function taking pointer-to-method regardless of constness函数采用指向方法的指针,而不考虑 constness
【发布时间】:2020-08-19 10:15:33
【问题描述】:

我想实现一个通用函数,它将引用对象和指向其成员函数的指针并调用它。但是,当我的类同时具有 const 和非 const 方法时,我无法这样做,因为我需要提供两个重载:

template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...))
{
    return (object.*method)(Us{}...);
}

template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...) const)
{
    return (object.*method)(Us{}...);
}

有没有办法只编写 1 个模板函数来接受 const 和非 const 方法指针,这样我就不必编写两次代码了?我正在使用 C++14。

从更广泛的角度来看,我最终想要实现的是传递第三个参数,一个数据缓冲区,将从中提取方法参数 - 因此模板函数尽可能通用地处理它。

【问题讨论】:

  • 如果你只有一个函数模板,你希望使用哪个成员函数?

标签: c++ templates c++14


【解决方案1】:

简短的回答是,不要自己实现这个,它已经以std::invoke的形式为你完成了:

#include <functional>

struct A {
    void foo(int x);
    void bar(int x) const;
};

void example() {
    A a;
    std::invoke(&A::foo, a, 3); 
    std::invoke(&A::bar, a, 3); 
}

回想起来你已经添加了一个 C++14 标签,std::invoke 的文档有一个示例实现,你可以在你的项目中使用它。

【讨论】:

  • 感谢您的回复!不幸的是,这并不能解决我的问题,就像我说的我被 C++14 困住了......
【解决方案2】:

这是一个不使用 std::function 的 C++14 替代方案。

我最终想要实现的是传递第三个参数,一个数据缓冲区,从中提取方法参数 - 因此模板函数尽可能通用地处理它

您在呼叫站点使用的内容将在这里完美转发:

template<typename Class, typename Func, typename... Args>
decltype(auto) callMethod_impl(Class& object, Func method, Args&&... args) {
    return (object.*method)(std::forward<Args>(args)...);
}


template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(Class& object, Ret(Class::*method)(Us...), Args&&... args) {
    return callMethod_impl(object, method, std::forward<Args>(args)...);
}

template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(const Class& object, Ret(Class::*method)(Us...) const, Args&&... args) {
    return callMethod_impl(object, method, std::forward<Args>(args)...);
}

Demo

如果您在callMethod_impl 中需要Ret,只需将其添加为模板参数,然后像callMethod 重载(Demo) 中的callMethod_impl&lt;Ret&gt;(...) 一样调用它。

【讨论】:

    【解决方案3】:

    没有std::invoke,您只能根据类型擦除做一些或多或少通用的解决方法。使用std::function 允许您创建代理函数以平等对待您的函数:

    #include <iostream>
    #include <functional>
    
    template<typename Ret, typename ...Us>
    Ret callMethod_impl(std::function<Ret(Us...)> f) {
        // common implementation here
        return f(Us{}...);
    }
    
    template<typename Ret, typename Class, typename ...Us>
    Ret callMethod(Class &object, Ret (Class::*method)(Us...)) {
        return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
    }
    
    template<typename Ret, typename Class, typename ...Us>
    Ret callMethod(const Class &object, Ret (Class::*method)(Us...) const) {
        return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
    }
    
    struct Foo {
        int bar() const { return 1; }
        float bar() { return 2.1f; };
    };
    
    int main() {
        Foo f;
        std::cout << callMethod(f, &Foo::bar) << std::endl;
    }
    

    请注意,volatile 函数(+ 组合)在此处不作处理,但也许您不需要完全通用性,而是需要实用的解决方案。

    【讨论】:

      猜你喜欢
      • 2023-04-01
      • 2014-07-21
      • 1970-01-01
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多