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

如何实现同时支持对象实例与指针的C++函数模板?

问题:实现同时支持对象实例与指针的函数模板

我需要实现一个可同时处理对象实例和指针的函数模板,这是后续开发可操作元素vector与元素指针vector函数的第一步。当前代码调用print_num传入指针时编译失败,相关代码、编译错误及编译器版本如下:

代码

#include <functional>
#include <iostream>

struct Foo
{
    int num_ = 42;
    void print_num() const { std::cout << num_ << std::endl; }
};


template<typename T> void print_num(const T & obj)
{
    std::invoke(&T::print_num, obj);
}

template<typename T> void print_num_ptr(const T * const obj)
{
    std::invoke(&T::print_num, obj);
}


int main(int argc, char * argv[])
{
    Foo foo;
    Foo * foo_ptr = &foo;

    print_num(foo); // 可正常运行
    print_num_ptr(foo_ptr); // 可正常运行
    print_num(foo_ptr); // 编译失败

    return 0;
}

编译错误

foo.cpp:14:18: error: type 'Foo *' cannot be used prior to '::' because it has no members
    std::invoke(&T::print_num, obj);
                 ^
foo.cpp:30:5: note: in instantiation of function template specialization 'print_num<Foo *>' requested here
    print_num(foo_ptr); // doesn't work
    ^
1 error generated.
make[2]: *** [CMakeFiles/foo.dir/foo.cpp.o] Error 1
make[1]: *** [CMakeFiles/foo.dir/all] Error 2
make: *** [all] Error 2

编译器版本

Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: x86_64-apple-darwin22.6.0
Thread model: posix


解决思路与修正代码

错误根源

当传入Foo*类型的指针时,模板参数T被推导为Foo*,此时&T::print_num试图访问指针类型的成员,但Foo*本身没有print_num成员,该成员属于底层的Foo类型,因此编译报错。

解决方案

使用C++标准库的类型萃取工具std::remove_pointer_t和std::decay_t获取底层对象类型,再引用该类型的成员函数指针,最后通过std::invoke调用——std::invoke会自动处理对象实例、指针甚至智能指针的调用逻辑。

修正后的代码

#include <functional>
#include <iostream>
#include <type_traits>

struct Foo
{
    int num_ = 42;
    void print_num() const { std::cout << num_ << std::endl; }
};

template<typename T> void print_num(const T & obj)
{
    // 提取底层对象类型,处理对象、指针、引用等情况
    using BaseType = std::remove_pointer_t<std::decay_t<T>>;
    std::invoke(&BaseType::print_num, obj);
}

int main(int argc, char * argv[])
{
    Foo foo;
    Foo * foo_ptr = &foo;

    print_num(foo);      // 正常运行
    print_num(foo_ptr);  // 现在可正常运行

    return 0;
}

简化说明

  • std::decay_t<T>用于处理可能的引用类型,确保得到纯净的类型(如const Foo&会被转换为Foo)
  • std::remove_pointer_t<T>用于将指针类型转换为底层对象类型(如Foo*转换为Foo)
  • 最终&BaseType::print_num获取正确的成员函数指针,std::invoke自动处理对象或指针的调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:43:10