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

C++成员函数首参类型推导疑问:取地址符作用与模板特化逻辑

MSVC C++20下成员函数指针的模板推导问题

问题代码

#include <tuple>

template <typename... Args>
struct args_holder
{
    using type = std::tuple<Args...>;
};

template <typename T>
struct base_holder;

template <typename Class, typename Proto, typename... Args>
struct base_holder<Proto(Class::*)(Args...)> : args_holder<Args...>
{
};

template <typename T>
using first_arg_type = std::tuple_element_t<0, typename base_holder<T>::type>;

struct test_struct
{
    void test_function(int x)
    {

    }
};

int main()
{
    static_assert(std::is_same_v<first_arg_type<decltype(test_struct::test_function)>, int>);
}

编译报错信息:

'type': is not a member of any direct or indirect base class of 'base_holder<void (int)>'

在test_struct::test_function前添加&后代码可正常编译运行。


问题解答

问题1:&的具体作用是什么?

&在这里是显式获取成员函数的指针。虽然IntelliSense显示的decltype结果看起来一致,但MSVC编译阶段的处理严格遵循C++标准:

  • 不加&时,test_struct::test_function是成员函数的名字,decltype作用于它时,得到的是普通函数类型void(int),而非成员函数指针类型。
  • 添加&后,会显式生成成员函数指针类型void(test_struct::*)(int),这才匹配你定义的base_holder特化模板。

IntelliSense的提示做了简化,和实际编译阶段的类型推导结果有差异,这是导致混淆的原因。

问题2:typename base_holder<T>::type的推导流程

整个推导过程分三步:

  1. 特化模板匹配:当T是成员函数指针类型(比如void(test_struct::*)(int))时,编译器会匹配base_holder的特化版本base_holder<Proto(Class::*)(Args...)>,并自动拆分这个复杂类型:
    • Class被推导为test_struct(成员函数所属的类)
    • Proto被推导为void(成员函数的返回值类型)
    • Args...被推导为int(成员函数的参数列表)
  2. 继承获取类型别名:这个特化的base_holder继承自args_holder<Args...>(也就是args_holder<int>),因此继承了args_holder中定义的type,即std::tuple<int>。
  3. 提取第一个参数类型:first_arg_type通过std::tuple_element_t<0, ...>从std::tuple<int>中取出第一个元素的类型,最终得到int。

如果T是普通函数类型(不加&时的void(int)),编译器会匹配base_holder的主模板,而主模板没有定义type成员,因此触发编译错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:21:17