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

如何简化C++模板调用,避免传递类成员指针的运行时开销?

如何消除类成员指针传递的运行时开销并简化模板调用

问题背景

先看原始代码:

using namespace std;

struct FS
{
    void print() { cout << "p\n"; }
    int s;
};

template <typename T, typename F>
void myInvoke(T& t, F f)
{
    invoke(f, t) = 10;
}

int main(int, char**) 
{
    FS fs;
    myInvoke(fs, &FS::s);
    cout << fs.s << "\n";
}

这里将类成员指针&FS::s作为函数参数传递,会带来不必要的运行时开销,我们希望把它转为编译期的模板参数,同时简化调用,避免手动指定成员类型。


最优解决方案(C++20)

C++20的auto非类型模板参数可以直接推导成员指针的类型,完美满足需求:

#include <functional>
#include <iostream>
using namespace std;

struct FS
{
    void print() { cout << "p\n"; }
    int s;
};

// 用auto自动推导成员指针的类型
template <typename T, auto f>
void myInvoke(T& t)
{
    invoke(f, t) = 30;
}

int main(int, char**) 
{
    FS fs;
    // 完全按你期望的方式调用,无需指定成员类型
    myInvoke<FS, &FS::s>(fs);
    cout << fs.s << "\n"; // 输出30
}

这里auto f会自动推导&FS::s的类型为int FS::*,编译器在编译期就确定了成员指针,彻底消除了运行时传递的开销。


C++17兼容写法

如果需要兼容C++17,可通过decltype和辅助模板实现:

#include <functional>
#include <iostream>
using namespace std;

struct FS
{
    void print() { cout << "p\n"; }
    int s;
};

// 内部实现模板
template <typename T, typename MemPtr, MemPtr f>
void myInvokeImpl(T& t)
{
    invoke(f, t) = 30;
}

// 辅助函数,自动推导成员指针类型
template <typename T, typename MemPtr>
constexpr auto makeMyInvoke(MemPtr f)
{
    return [](T& t) { myInvokeImpl<T, MemPtr, f>(t); };
}

int main(int, char**) 
{
    FS fs;
    auto invokeS = makeMyInvoke<FS>(&FS::s);
    invokeS(fs);
    cout << fs.s << "\n"; // 输出30
}

这种写法需要先创建绑定后的函数对象再调用,不如C++20方案直接,优先推荐前者。


为什么原始写法需要指定typename P?

你最初的模板template <typename T, typename P, P FS::* f>中,P是成员变量的类型,C20之前编译器无法从&FS::s自动推导P,必须显式指定;而C20的auto非类型模板参数可以直接推导整个成员指针的类型,从而省去了手动指定P的步骤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:24:40