【问题标题】:function to retrieve member function pointer with n arguments检索具有 n 个参数的成员函数指针的函数
【发布时间】:2022-09-20 17:08:23
【问题描述】:

我需要实现一个函数来检索具有 n 个参数的重载成员函数的函数指针。所以例如对于以下课程:

struct Test
{
    int func(int i1);
    int func(int i1, int i2);
    int func(int i1, int i2, int i3);
};

我需要检索Test::func 的一个特定重载。我已经有以下实现:

template<int Num> struct Overload {};


template<> struct Overload<0>
{
    template<class Ret, class Class>
    static auto from(Ret (*func)()) { return func; }

    template<class Ret, class Class>
    static auto from(Ret (Class::*meth)()) { return meth; }

    template<class Ret, class Class>
    static auto from(Ret (Class::*meth)() const) { return meth; }
};

template<> struct Overload<2>
{
    template<class Ret, class Class, class Arg1, class Arg2>
    static auto from(Ret (*func)(Arg1, Arg2)) { return func; }

    template<class Ret, class Class, class Arg1, class Arg2>
    static auto from(Ret (Class::*meth)(Arg1, Arg2)) { return meth; }

    template<class Ret, class Class, class Arg1, class Arg2>
    static auto from(Ret (Class::*meth)(Arg1, Arg2) const) { return meth; }
};

此实现按预期工作,但需要为每个参数计数单独实现。 据我了解,这需要https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4072.html 被拒绝,但我可能会遗漏一些东西。有没有办法从 C++17/C++20 中的模板参数Num 派生参数?

编辑:关于 cmets / 答案的一些说明

  1. 为什么不直接使用参数作为模板参数: 我已经为此目的提供了一个功能:
    template<class... Args> struct OverloadArgs
    {
        template<class Ret>
        static auto from(Ret (*func)(Args...)) {return func;}
        ...
    };
    

    例如。对于 swizzling,我只是有多个具有不同 arg 计数的重载,指定 Overload&lt;4&gt;::from(&amp;Test::swizzle) 而不是 OverloadArgs&lt;int, int, int, int&gt;::from(&amp;Test::swizzle) 要简洁得多

    1. 这用于将函数/类包装到 Python。如 1) 中所述,在某些情况下,重载 arg 计数而不是 arg 类型会更简洁,这就是我想要两者兼有的原因。
  • 出于好奇,您打算如何处理采用相同数量但不同类型参数的重载?
  • 我有一个类似的实现,它直接允许用户指定 arg 类型:template&lt;class... Args&gt; struct OverloadArgs
  • 看看std::mem_fn。您可能只需要在其模板中指定函数签名,以便它可以执行重载决议。即auto memptr1 = std::mem_fn&lt;int(int)&gt;(&amp;Test::func)auto memptr2 = std::mem_fn&lt;int(int, int)&gt;(&amp;Test::func)
  • 类型是否仅限于int? (在这种情况下,std::index_sequence 和 \"using always_t&lt;I, T&gt; = T;\" 可能会成功)。
  • 类型不限于 int。通常它将是同一类型的 n 倍,因为对于不同的类型,OverloadArgs impl 可能更具可读性。

标签: c++ c++17


【解决方案1】:

您可以指定参数类型,而不是指定参数的数量

template<class... Args> struct Overload
{
    template<class Ret, class Class>
    static auto from(Ret(Class::* meth)(Args...)) { return meth; }
};

int main()
{
     Test t;  
     auto p2 = Overload<int, int>::from(&Test::func);  
     auto p0 = Overload<>::from(&Test::func);
     (t.*p0)();
     (t.*p2)(1,2);

    return 0;
}

UPD

嗯...我的知识只够下面的提议

#define Overload_0 Overload<>
#define Overload_1 Overload<int>
#define Overload_2 Overload<int,int>

int main()
{
     Test t;  
     auto p2 = Overload_2::from(&Test::func);
     auto p0 = Overload_0::from(&Test::func);
     (t.*p0)();
     (t.*p2)(1,2);
     
    return 0;
}

【讨论】:

  • 我已经有这样的课了。但是在某些情况下,我想仅根据 arg 计数进行重载。
  • @maxbachmann 我不知道在您的情况下是否有任何元编程可以解决问题。我最好的想法是使用预处理器
  • 是的,这就是我现在所做的。这不是最漂亮的东西,但确实有效
【解决方案2】:

我不确定我是否完全理解你的目标,但我认为parameter pack 可以解决这个问题。 模板参数包(在本例中名为 Args)允许您传递可变数量的参数。

struct Test {
    int func(int i1);
    int func(int i1, int i2);
    int func(int i1, int i2, int i3);
};

template<class Ret, class Class, class... Args>
auto From(Ret(Class::*meth)(Args...)) {
    return meth;
}

int main() {
    Test t;
    auto f = From<int, Test, int, int, int>(&Test::func);
    int result = std::invoke(f, t, 10, 11, 12);
}

我很好奇您打算如何使用它,但可能有一种不同且更好的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    相关资源
    最近更新 更多