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

如何将非静态成员函数或捕获类实例的Lambda作为类模板的模板参数?

解决类模板中使用非静态成员函数或带捕获Lambda作为模板参数的问题

你的问题核心在于原模板wrapper的参数要求是无参的普通函数指针,但非静态成员函数和带捕获的Lambda都不符合这个签名:

  • 非静态成员函数隐含了一个this指针参数,实际签名是std::string (bar::*)(),和模板期望的std::string (*)()不匹配;
  • 捕获外部变量(比如this)的Lambda无法转换为普通函数指针,只有无捕获的Lambda才能做这种转换。

下面提供几种可行的修改方案:

方案1:修改模板以支持成员函数指针和实例绑定

我们可以调整wrapper模板,让它同时接受成员函数指针和类实例的类型,然后在调用时绑定实例:

#include <iostream>

// 通用版本:支持成员函数指针
template<typename T, std::string (T::*Fun)()>
struct member_wrapper {
    T* instance;
    member_wrapper(T* inst) : instance(inst) {}
    
    void operator()() {
        std::cout << "wrapped " << (instance->*Fun)() << std::endl;
    }
};

// 保留原版本支持普通函数
template<std::string (*Fun)()>
struct wrapper {
    void operator()() {
        std::cout << "wrapped " << Fun() << std::endl;
    }
};

std::string foo() { return "foo"; }

struct bar {
    static std::string str1() { return "bar1"; }
    wrapper<str1> wrapped_bar1;

    std::string str2() { return "bar2"; }
    // 使用成员函数版本的wrapper,初始化时传入this
    member_wrapper<bar, &bar::str2> wrapped_bar2;

    bar() : wrapped_bar2(this) {}
};

int main() {
    wrapper<foo> wrapped;
    wrapped();

    bar some_bar;
    some_bar.wrapped_bar1();
    some_bar.wrapped_bar2(); // 现在可以正常调用
}

方案2:让模板支持任意可调用对象(更通用)

如果希望wrapper能兼容所有可调用类型(普通函数、成员函数、Lambda、仿函数等),可以把模板参数改成可调用对象的类型,然后在wrapper中存储该对象的实例:

#include <iostream>
#include <functional>

template<typename Callable>
struct wrapper {
    Callable func;
    wrapper(Callable f) : func(std::move(f)) {}
    
    void operator()() {
        std::cout << "wrapped " << func() << std::endl;
    }
};

// 辅助函数简化构造(可选)
template<typename Callable>
auto make_wrapper(Callable&& f) {
    return wrapper<std::decay_t<Callable>>(std::forward<Callable>(f));
}

std::string foo() { return "foo"; }

struct bar {
    static std::string str1() { return "bar1"; }
    wrapper<decltype(&bar::str1)> wrapped_bar1{&bar::str1};

    std::string str2() { return "bar2"; }
    // 绑定this到成员函数
    wrapper<std::function<std::string()>> wrapped_bar2;

    bar() : wrapped_bar2([this]() { return this->str2(); }) {}
};

int main() {
    auto wrapped = make_wrapper(foo);
    wrapped();

    bar some_bar;
    some_bar.wrapped_bar1();
    some_bar.wrapped_bar2(); // 正常调用带捕获的Lambda绑定的成员函数
}

这个方案灵活性最高,几乎支持所有可调用类型,包括带捕获的Lambda。

方案3:使用无捕获Lambda包装成员函数(仅限特定场景)

如果你坚持要把函数作为模板参数传递,可以用无捕获的Lambda,通过将实例指针作为参数传递(但需要修改wrapper的调用逻辑):

#include <iostream>

template<std::string (*Fun)(void*)>
struct wrapper {
    void* instance;
    wrapper(void* inst) : instance(inst) {}
    
    void operator()() {
        std::cout << "wrapped " << Fun(instance) << std::endl;
    }
};

std::string foo() { return "foo"; }

struct bar {
    static std::string str1() { return "bar1"; }
    wrapper<[](void*){ return bar::str1(); }> wrapped_bar1{nullptr};

    std::string str2() { return "bar2"; }
    // 无捕获Lambda包装成员函数,通过void*传递this
    static std::string str2_wrapper(void* inst) {
        return static_cast<bar*>(inst)->str2();
    }
    wrapper<str2_wrapper> wrapped_bar2{this};

    bar() : wrapped_bar2(this) {}
};

int main() {
    wrapper<[](void*){ return foo(); }> wrapped{nullptr};
    wrapped();

    bar some_bar;
    some_bar.wrapped_bar1();
    some_bar.wrapped_bar2();
}

这种方案比较繁琐,仅适合必须用模板参数传递函数的场景,不推荐作为通用方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:19:05