函数采用指向方法的指针,而与常量无关

问题描述

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

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

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

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

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

解决方法

简短的答案是,不要自己实现,它已经以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,3); 
}

回顾一下,您已经添加了C ++ 14标记,std::invoke的文档提供了一个示例实现,可以在您的项目中使用。

,

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

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

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

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... Args>
Ret callMethod(const Class& object,Ret(Class::*method)(Us...) const,std::forward<Args>(args)...);
}

Demo

如果在Ret中需要callMethod_impl,只需将其添加为模板参数,然后从callMethod_impl<Ret>(...)重载(Demo)中调用callMethod即可。

,

如果没有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 ...Us>
Ret callMethod(Class &object,Ret (Class::*method)(Us...)) {
    return callMethod_impl(std::function<Ret(Us...)>(std::bind(method,object)));
}

template<typename Ret,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函数(+组合),但是也许您不需要完全的通用性,而是务实的解决方案。