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

模板类型的方法调用:兼容指针类型与派生检查问题

问题与解决方案

首先是定义的Policy基类:

template<typename Type>
struct Policy {
    virtual bool cause() = 0;
    virtual void implement(std::shared_ptr<Type> type) = 0;
};

初始实现的integrate方法:

template<template<typename> typename TPolicy, typename TObj>
void integrate(TPolicy<TObj>&& policy, std::shared_ptr<TObj> val) {
   if (policy.cause())
       policy.implement(val);
}

面临两个问题:

  1. 如何让integrate()同时支持Policy<T>*、shared_ptr<Policy<T>>等指针类型作为参数?当前实现的.运算符不支持指针调用。
  2. 如何在编译期检查TPolicy是否确实派生自Policy<T>?

问题1:支持多种指针/引用类型的参数处理

核心是统一成员函数的访问方式,以下两种方案可选:

方案1:自定义解引用辅助模板

编写通用的解引用函数,把不同类型的参数转换成对象引用:

// 处理普通引用
template<typename T>
T& deref(T& obj) {
    return obj;
}

// 处理原始指针
template<typename T>
T& deref(T* ptr) {
    return *ptr;
}

// 处理shared_ptr
template<typename T>
T& deref(const std::shared_ptr<T>& ptr) {
    return *ptr;
}

// 扩展支持unique_ptr
template<typename T>
T& deref(const std::unique_ptr<T>& ptr) {
    return *ptr;
}

修改integrate函数,用辅助函数统一访问:

template<typename TPolicy, typename TObj>
void integrate(TPolicy&& policy, std::shared_ptr<TObj> val) {
    auto& policy_ref = deref(std::forward<TPolicy>(policy));
    if (policy_ref.cause()) {
        policy_ref.implement(val);
    }
}

方案2:使用C++17的std::invoke

std::invoke会自动处理对象、指针、智能指针的调用逻辑,无需手动写解引用:

#include <functional>

template<typename TPolicy, typename TObj>
void integrate(TPolicy&& policy, std::shared_ptr<TObj> val) {
    if (std::invoke(&Policy<TObj>::cause, std::forward<TPolicy>(policy))) {
        std::invoke(&Policy<TObj>::implement, std::forward<TPolicy>(policy), val);
    }
}

问题2:编译期检查派生关系

方案1:static_assert + std::is_base_of(C++11及以上)

通过类型特性提取真实的Policy类型,再做编译期断言:

#include <type_traits>

template<typename TPolicy, typename TObj>
void integrate(TPolicy&& policy, std::shared_ptr<TObj> val) {
    // 移除引用和const/volatile限定符
    using RawPolicy = std::remove_cv_t<std::remove_reference_t<TPolicy>>;
    // 提取指针/智能指针指向的原始类型
    using ActualPolicy = std::conditional_t<
        std::is_pointer_v<RawPolicy>,
        std::remove_pointer_t<RawPolicy>,
        std::conditional_t<
            std::is_same_v<RawPolicy, std::shared_ptr<typename RawPolicy::element_type>>,
            typename RawPolicy::element_type,
            RawPolicy
        >
    >;

    // 编译期断言,确保派生关系
    static_assert(std::is_base_of_v<Policy<TObj>, ActualPolicy>, 
                  "传入的Policy类型必须派生自Policy<TObj>");

    auto& policy_ref = deref(std::forward<TPolicy>(policy));
    if (policy_ref.cause()) {
        policy_ref.implement(val);
    }
}

方案2:C++20概念约束

用概念直接约束模板参数,错误信息更友好:

#include <concepts>
#include <functional>

// 定义概念:验证类型是否符合Policy<TObj>的接口
template<typename TPolicy, typename TObj>
concept PolicyCompatible = requires(TPolicy policy, std::shared_ptr<TObj> val) {
    std::invoke(&Policy<TObj>::cause, policy);
    std::invoke(&Policy<TObj>::implement, policy, val);
};

template<PolicyCompatible<TObj> TPolicy, typename TObj>
void integrate(TPolicy&& policy, std::shared_ptr<TObj> val) {
    if (std::invoke(&Policy<TObj>::cause, std::forward<TPolicy>(policy))) {
        std::invoke(&Policy<TObj>::implement, std::forward<TPolicy>(policy), val);
    }
}

这个概念不仅检查派生关系,还直接验证成员函数的可调用性,适用性更强。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:07:15