是否可以使用方便的语法来调用具有成员函数指针的函数?

时间:2017-09-24 17:58:22

标签: c++

请查看此非编译代码段:

struct Object {
    template <RETURN (OBJECT::*MEMFN)(PARAMETERS...), typename RETURN, typename OBJECT, typename ...PARAMETERS>
    void call() {
    }
};

struct Foo {
    void fn();
};

int main() {
    Object o;
    o.call<&Foo::fn>();
}

基本上,我想要实现的是拥有一个函数(Object::call),它专门用于任何类型的成员函数指针,并且具有方便的语法来调用。

我找到的最近的解决方案就是这个,这非常难看:

struct Object {
};

template <typename MEMFNTYPE, MEMFNTYPE MEMFN>
struct Caller;

template <typename RETURN, typename OBJECT, typename ...PARAMETERS, RETURN (OBJECT::*MEMFN)(PARAMETERS...)>
struct Caller<RETURN (OBJECT::*)(PARAMETERS...), MEMFN> {
    Object *object;

    Caller(Object &o) : object(&o) { }

    void call() {
        // I have the necessary information here: the member function pointer as template parameter, and a pointer to Object
    }
};

struct Foo {
    void fn();
};

int main() {
    Object o;

    Caller<decltype(&Foo::fn), &Foo::fn>(o).call();
}

这个问题有更好的解决方案吗?

(原因是我尝试这样做是因为我想为其他成员函数创建包装函数(call))

Kerrek SB建议使用auto,我试过这个:

struct Object {
    template <auto MEMFN>
    void call();

    template <auto MEMFN, typename RETURN, typename OBJECT, typename ...PARAMETERS>
    void call<RETURN (OBJECT::*MEMFN)(PARAMETERS...)>() {
    }
};

struct Foo {
    void fn();
};

int main() {
    Object o;
    o.call<&Foo::fn>();
}

但是,这不会编译(我是否需要以不同方式添加MEMFN到模板参数列表(而不是auto MEMFN?):

t2.cpp:6:7: error: parse error in template argument list
  void call<RETURN (OBJECT::*MEMFN)(PARAMETERS...)>() {
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
t2.cpp:6:52: error: non-class, non-variable partial specialization ‘call<<expression error> >’ is not allowed
  void call<RETURN (OBJECT::*MEMFN)(PARAMETERS...)>() {

1 个答案:

答案 0 :(得分:2)

正如评论中所建议的,如果你接受C ++ 17解决方案,那么auto就是你的朋友。 <type_traits>if constexpr

也是如此
#include <type_traits>
#include <iostream>

struct Object {
    template <auto MEMFN>
    void call() {
        if constexpr (std::is_member_function_pointer_v<decltype(MEMFN)>)
            std::cout << "Is member\n";
    }
};

struct Foo {
    void fn();
};

int main() {
    Object o;
    o.call<&Foo::fn>();
}

如果类型特征确实是这样,函数体将只发出将参数视为成员函数指针的代码。不需要专业化。