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); }
关键说明
- 主模板使用
auto Method作为非类型参数,让编译器自动推导成员方法的完整类型,无需手动指定参数列表。 - 通过偏特化匹配
void(Owned::*)(Args...)类型的成员方法,自动提取出参数包Args...。 - 利用
std::forward实现参数完美转发,保证参数传递的正确性(尤其是左值/右值属性)。 - 生成的
std::function会自动匹配成员方法的参数签名,无需手动指定。
修改后Bind结构体可支持任意参数列表的void返回值成员方法,同时满足constexpr上下文创建函数指针的需求。
内容的提问来源于stack exchange,提问作者corysama
相关产品推荐
相关产品推荐

