【问题标题】:how to write this function in C++ using meta programming如何使用元编程在 C++ 中编写此函数
【发布时间】:2021-10-21 15:41:07
【问题描述】:

你想达到什么目的

我想将 RetType ClassA::MemberFunc(Args...) 转换为 mem_fn(&ClassA::MemberFunc) 但它就像一个函数,以避免为每个成员函数编写 lambda 或函数

你得到了什么(包括错误信息)

no matching function for call to ‘regisAdd(std::_Mem_fn<int (ABC::*)(int, int)>)’

这是我的代码。

#include <functional>
#include <iostream>

using namespace std;

struct ABC {
    int value;
    int add(int a, int b) {
        return a + b * value;
    }
    int other(int a) {
        return a * value;
    }
};

int doAdd(void* data, int a, int b) {
    ABC* p = (ABC*)data;
    return p->add(a, b);
}

typedef int (*TYPE_ADD)(void* data, int a, int b);
TYPE_ADD gAdd = nullptr;
void regisAdd(TYPE_ADD a) {
    gAdd = a;
}

void callAdd() {
    if (!gAdd) return;
    ABC abc;
    abc.value = 10;
    cout << gAdd(&abc, 1, 2) << endl;
}

typedef int (*TYPE_OTHER)(void* data, int a);
TYPE_OTHER gOther = nullptr;
void regisOther(TYPE_OTHER a) {
    gOther = a;
}
void callOther() {
    if (!gOther) return;
    ABC abc;
    abc.value = 10;
    cout << gOther(&abc, 12) << endl;
}

int main() {
    regisAdd(doAdd);                               // this is GOOD
    callAdd();                                     // call
    regisAdd([](void* data, int a, int b) {        // < this is also GOOD
        return static_cast<ABC*>(data)->add(a, b); // < GOOD
    });                                            // < GOOD
    callAdd();                                     // call

    // how to write a general function work like mem_fn
    // to avoid write doAdd and lambda for every function signatures
    // regisAdd(mem_fn(&ABC::add));
    // regisOther(mem_fn(&ABC::other));
    // callAdd();
    return 0;
}

【问题讨论】:

  • 你如何为callXXX选择参数?
  • @Jarod42,这是简单的代码,真实世界的代码是有几个用 C 编写的函数指针成员的结构,我想将它们包装到 C++。

标签: c++ templates template-meta-programming


【解决方案1】:

据我了解,您想要这样的东西:

template <auto mem> // C++17, else <typename T, T mem>
struct mem_to_func;

template <typename C, typename Ret, typename ... Args,
          Ret (C::*m)(Args...)>
struct mem_to_func<m>
{
    static Ret func_ptr(C* c, Args... args)
    {
        return (c->*m)(std::forward<Args>(args)...);
    }
    static Ret func_ref(C& c, Args... args)
    {
        return (c.*m)(std::forward<Args>(args)...);
    }
    static Ret func_voidp(void* p, Args... args)
    {
        auto* c = static_cast<C*>(p);
        return (c->*m)(std::forward<Args>(args)...);
    }
};

template <typename C, typename Ret, typename ... Args,
          Ret (C::*m)(Args...) const>
struct mem_to_func<m>
{
    static Ret func(const C* c, Args... args)
    {
        return (c->*m)(std::forward<Args>(args)...);
    }
    static Ret func_ref(const C& c, Args... args)
    {
        return (c.*m)(std::forward<Args>(args)...);
    }
    static Ret func_voidp(const void* p, Args... args)
    {
        const auto* c = static_cast<const C*>(p);
        return (c->*m)(std::forward<Args>(args)...);
    }
};
// Others specializations for combination with
// - volatile,
// - reference to this,
// - and C-ellipsis... 

然后

regisAdd(mem_to_func<&ABC::add>::func_voidp);

【讨论】:

  • 太好了!,我会接受这个答案,只有两个后续问题,1> auto mem 很神奇,当我更改为typename T, T mem。代码未编译。你能给我更多的细节吗? 2> 是否可以将mem_to_func&lt;&amp;ABC::add&gt;::func_voidp 包装成一个函数?
  • 如果你在 C++11/C++14 中,应该使用&lt;typename T, T mem&gt;,但也应该为了专业化而改变它。 mem_to_func&lt;&amp;ABC::add&gt;::func_voidp 是一个函数。
  • 可以,但是可以像mem_fn(&amp;ABC::add)一样包装成函数吗?
  • (假设 C++17 和 template &lt;auto&gt;),mem_fn&lt;&amp;ABC::add&gt; 可能是可能的(否则 mem_fn&lt;decltype(&amp;ABC::add), &amp;ABC::add&gt;)。 mem_fn(&amp;ABC::add) 语法需要 MACRO(在上面重定向或直接在 mem_to_func&lt;&amp;ABC::add&gt;::func_voidp 上重定向)。
猜你喜欢
  • 2012-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-04
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多