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

扩展类型擦除:C++17中同时约束类型具备飞行与打印能力的实现方法

扩展类型擦除:C++17中同时约束类型具备飞行与打印能力的实现方法

你好!要在C++17里实现同时约束类型具备飞行(fly)和打印(print)能力的类型擦除,核心思路就是把两个操作的抽象接口合并,再做对应的适配层。我来一步步给你拆解实现方法:

第一步:补全并实现Printing相关的类型擦除组件

先把你已经有的Flying相关代码补全,然后照着这个对称结构实现Printing的类型擦除组件:

#include <iostream>
#include <memory>
#include <type_traits>
#include <utility>

// 补全你已有的Flying相关代码
class FlyingConcept {
public:
    virtual ~FlyingConcept() = default;
    virtual void fly() = 0;
};

template <typename T>
class FlyingModel : public FlyingConcept {
public:
    FlyingModel(T t) : t{std::forward<std::decay_t<T>>(t)} {}
    void fly() override { t.fly(); }
private:
    std::decay_t<T> t;
};

class AnyFlyer {
public:
    template <typename T>
    AnyFlyer(T t) : flyingConcept{std::make_unique<FlyingModel<std::decay_t<T>>>(std::forward<std::decay_t<T>>(t))} {}
    void fly() { flyingConcept->fly(); }
private:
    std::unique_ptr<FlyingConcept> flyingConcept;
};

// 新增Printing相关的类型擦除组件,和Flying结构完全对称
class PrintingConcept {
public:
    virtual ~PrintingConcept() = default;
    virtual void print() = 0;
};

template <typename T>
class PrintingModel : public PrintingConcept {
public:
    PrintingModel(T t) : t{std::forward<std::decay_t<T>>(t)} {}
    void print() override { t.print(); }
private:
    std::decay_t<T> t;
};

class AnyPrinter {
public:
    template <typename T>
    AnyPrinter(T t) : printingConcept{std::make_unique<PrintingModel<std::decay_t<T>>>(std::forward<std::decay_t<T>>(t))} {}
    void print() { printingConcept->print(); }
private:
    std::unique_ptr<PrintingConcept> printingConcept;
};

第二步:实现同时支持飞行和打印的组合类型擦除

现在要把两个能力合并,核心是定义一个同时包含fly()和print()的抽象接口,再实现对应的适配模型,让它能包装任意同时具备这两个能力的类型:

// 组合抽象接口:同时要求fly和print两个操作的纯虚函数
class FlyingAndPrintingConcept {
public:
    virtual ~FlyingAndPrintingConcept() = default;
    virtual void fly() = 0;
    virtual void print() = 0;
};

// 组合模型:适配任意同时具备fly和print能力的类型T
template <typename T>
class FlyingAndPrintingModel : public FlyingAndPrintingConcept {
public:
    // 用完美转发处理左值、右值等各种参数类型
    template <typename U>
    FlyingAndPrintingModel(U&& t) : t_{std::forward<U>(t)} {}

    void fly() override { t_.fly(); }
    void print() override { t_.print(); }

private:
    std::decay_t<T> t_;
};

// 对外使用的统一类型:让用户无需关心内部细节,直接调用操作
class AnyFlyerPrinter {
public:
    template <typename T>
    AnyFlyerPrinter(T&& t) 
        : concept_ptr_{std::make_unique<FlyingAndPrintingModel<std::decay_t<T>>>(std::forward<T>(t))}
    {
        // C++17不能用concepts,用静态断言在编译期就检查类型是否符合要求
        static_assert(std::is_invocable_r_v<void, decltype(&T::fly), T>, "传入的类型必须具备fly()方法");
        static_assert(std::is_invocable_r_v<void, decltype(&T::print), T>, "传入的类型必须具备print()方法");
    }

    // 对外暴露统一的操作接口
    void fly() { concept_ptr_->fly(); }
    void print() { concept_ptr_->print(); }

private:
    std::unique_ptr<FlyingAndPrintingConcept> concept_ptr_;
};

第三步:测试代码验证功能

咱们写两个具备双能力的测试类,验证一下这个实现是否能正常工作:

// 测试用例1:会飞还会自我介绍的小鸟
class Bird {
public:
    void fly() { std::cout << "小鸟扑棱着翅膀飞起来啦!\n"; }
    void print() { std::cout << "大家好~我是一只小麻雀!\n"; }
};

// 测试用例2:会悬停还能报状态的无人机
class Drone {
public:
    void fly() { std::cout << "无人机稳定悬停在10米高空!\n"; }
    void print() { std::cout << "当前电量:85%,信号强度:满格\n"; }
};

int main() {
    AnyFlyerPrinter sparrow{Bird{}};
    sparrow.fly();
    sparrow.print();

    AnyFlyerPrinter quadcopter{Drone{}};
    quadcopter.fly();
    quadcopter.print();

    // 如果传入不符合要求的类型,编译期会直接触发静态断言报错
    // AnyFlyerPrinter invalid{int{}}; // 取消注释会看到编译错误
    return 0;
}

额外小提示

  • 静态断言的作用:在编译期就拦截不符合要求的类型,避免等到运行时才发现问题,这是C++17里替代concepts做类型约束的常用手段。
  • std::decay_t和完美转发:确保我们能正确处理左值、右值、const修饰的各种参数,避免不必要的拷贝操作。
  • 为什么不直接多继承两个Concept?其实也可以这么做,但直接定义一个包含双操作的统一抽象类,代码会更简洁,也更符合类型擦除的单一接口原则。

备注:内容来源于stack exchange,提问作者Mohammed Li

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 14:28:04