You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++17下修改Bind结构体以支持任意参数成员方法作为模板参数

C++17 实现支持任意参数成员方法的Bind结构体

需要修改下方的struct Bind,使其能够处理带任意参数的成员方法(方法返回值始终为void)。目标是在constexpr上下文创建函数指针,后续可在非constexpr上下文用于创建std::functions。

原始代码:

#include <functional>

template <typename Owner, typename Owned, Owned Owner::* Member, void(Owned::* Method)(int)>
struct Bind {
    static auto apply(Owner* owner) {
        return std::function<void(int)>( [=](int x) { ((owner->*Member).*Method)(x); } );
    }
};

struct Foo {
    void x(int x) { }
    void y(float y, int x) { }
};

struct Bar {
    Foo foo1;
    Foo foo2;
};

int main() {
    Bar bar;

    std::function<void(int)> (*bindX)(Bar* owner) = &Bind<Bar, Foo, &Bar::foo1, &Foo::x>::apply;
    std::function<void(int)> targetX = bindX(&bar);
    targetX(42);


    std::function<void(float, int)> (*bindY)(Bar* owner) = &Bind<Bar, Foo, &Bar::foo2, &Foo::y>::apply;
    std::function<void(float, int)> targetY = bindY(&bar);
    targetY(3.14f, 42);
}

当前报错:

error: could not convert template argument '&Foo::y' from 'void (Foo::)(float, int)' to 'void (Foo::)(int)'

上述代码展示了两种参数列表示例,但Bind需要支持编译期固定的任意函数签名的方法。

尝试过的写法及报错:

  • 将Args...放在模板参数中间,报错:error: parameter pack 'Args' must be at the end of the template parameter list
  • 尝试模板化的非类型参数写法,报错:expected 'class' or 'typename' before 'void'

疑问:是否存在“模板化模板非类型参数”?另外,template <auto Method>似乎适用,但不知如何匹配lambda的签名。


解决方案

利用C++17的auto非类型模板参数和可变参数模板,可重构Bind结构体自动适配任意参数列表:

#include <functional>

// 主模板:用auto推导成员方法类型
template <typename Owner, typename Owned, Owned Owner::* Member, auto Method>
struct Bind;

// 偏特化:匹配void返回值的成员方法,提取参数包
template <typename Owner, typename Owned, Owned Owner::* Member, typename... Args>
struct Bind<Owner, Owned, Member, void(Owned::*)(Args...)> {
    static auto apply(Owner* owner) {
        return std::function<void(Args...)>(
            [owner](Args... args) {
                ((owner->*Member).*Method)(std::forward<Args>(args)...);
            }
        );
    }
};

struct Foo {
    void x(int x) { }
    void y(float y, int x) { }
};

struct Bar {
    Foo foo1;
    Foo foo2;
};

int main() {
    Bar bar;

    std::function<void(int)> (*bindX)(Bar*) = &Bind<Bar, Foo, &Bar::foo1, &Foo::x>::apply;
    auto targetX = bindX(&bar);
    targetX(42);

    std::function<void(float, int)> (*bindY)(Bar*) = &Bind<Bar, Foo, &Bar::foo2, &Foo::y>::apply;
    auto targetY = bindY(&bar);
    targetY(3.14f, 42);
}

关键说明

  1. 主模板使用auto Method作为非类型参数,让编译器自动推导成员方法的完整类型,无需手动指定参数列表。
  2. 通过偏特化匹配void(Owned::*)(Args...)类型的成员方法,自动提取出参数包Args...。
  3. 利用std::forward实现参数完美转发,保证参数传递的正确性(尤其是左值/右值属性)。
  4. 生成的std::function会自动匹配成员方法的参数签名,无需手动指定。

修改后Bind结构体可支持任意参数列表的void返回值成员方法,同时满足constexpr上下文创建函数指针的需求。

内容的提问来源于stack exchange,提问作者corysama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 20:23:11