新聞中心

EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 解說(shuō)C++ 的類型擦除:std::function 和std::any

解說(shuō)C++ 的類型擦除:std::function 和std::any

作者:嵌入式經(jīng)驗(yàn)分享 時(shí)間:2025-08-04 來(lái)源:今日頭條 收藏

編程中,我們經(jīng)常會(huì)遇到需要編寫?yīng)毩⒂谄洳僮黝愋停òú煌瘮?shù)類型和變量類型)的情況(類似于C語(yǔ)言中的回調(diào)函數(shù),但是能適配任意類型)。這時(shí), (Type Erasure) 就派上用場(chǎng)了,它讓我們能夠以統(tǒng)一的方式處理各種類型。本文將探討的定義、工作原理,并提供實(shí)現(xiàn) std::function 和 std::any 的示例。

什么是

類型擦除是一種無(wú)需繼承或模板即可實(shí)現(xiàn)多態(tài)性的語(yǔ)言規(guī)范。它隱藏了對(duì)象的具體類型,只暴露一個(gè)統(tǒng)一的接口。這使我們能夠通過(guò)一個(gè)通用接口存儲(chǔ)、傳遞和操作不同類型的對(duì)象,而無(wú)需在編譯時(shí)知道具體類型。

為什么使用類型擦除

類型擦除有幾個(gè)主要優(yōu)點(diǎn):

靈活性:你可以通過(guò)一個(gè)接口處理不同類型的對(duì)象。

解耦:使用類型擦除對(duì)象的代碼在編譯時(shí)無(wú)需知道具體類型。

多態(tài)性:無(wú)需繼承即可實(shí)現(xiàn)運(yùn)行時(shí)的多態(tài)性,從而更容易地處理不共享公共基類的現(xiàn)有類型。

實(shí)現(xiàn)類型擦除:std::function 和 std::any

標(biāo)準(zhǔn)庫(kù)提供了 std::function 和 std::any,它們是類型擦除的示例。一起看看它們的工作原理。

簡(jiǎn)化的 std::function

std::function 是一個(gè)多功能的可調(diào)用對(duì)象包裝器。它可以存儲(chǔ)函數(shù)、lambda 表達(dá)式或定義了()運(yùn)算操作符的對(duì)象。std::function 的關(guān)鍵特性在于它隱藏了可調(diào)用對(duì)象的類型,從而統(tǒng)一了調(diào)用接口。

示例:

#include <iostream>#include <memory>#include <utility>class CallableBase { //沒(méi)有類型的接口類public:    virtual ~CallableBase() = default;    virtual void call() const = 0; //純虛函數(shù)};template <typename T>  //用這個(gè)子類對(duì)接口類重載,賦值具體類型的函數(shù)class CallableWrapper : public CallableBase{public:
   CallableWrapper(T callable) :callable_(std::move(callable)) {}    void call() const override {
       callable_();
}private:
   T callable_;
};class SimpleFunction{public:template <typename T>
SimpleFunction(T callable): //創(chuàng)建時(shí)賦值初始化
callableImpl_(std::make_shared<CallableWrapper<T>>(std::move(callable))) {}void operand() const {//()操作符
   if(callableImpl_)
    callableImpl_->call();
}private:    std::shared_ptr<CallableBase> callableImpl_; //無(wú)類型的接口變量};void helloFunction(){    std::cout <<"Hello, function !!! n";
}int main(){
   SimpleFunction f1 = helloFunction;
   SimpleFunction f2 = [](){std::cout << "Hello, Lambda !!!n";};
   f1(); //輸出:Hello, Function !!!
   f2(); //輸出:Hello, Lambda !!!
   return 0;
}

在此例中,SimpleFunction 用于存儲(chǔ)常規(guī)函數(shù)和lambda 表達(dá)式。被調(diào)用函數(shù)的實(shí)際類型被擦除了,并且 SimpleFunction 提供了一種統(tǒng)一的方法來(lái)調(diào)用存儲(chǔ)的函數(shù)。

簡(jiǎn)化的 std::any

std::any 是一個(gè)類型安全的容器,可容納任何類型的單個(gè)值。它可以存儲(chǔ)任何類型的對(duì)象,并且可以使用類型安全的強(qiáng)制類型轉(zhuǎn)換來(lái)檢索存儲(chǔ)的值。

#include <iostream>
#include <memory>
#include <utility>
#include <typeinfo>
#include <typeindex>class AnyBase{public:
   virtual ~AnyBase() = default;
   virtual std::type_index type() const = 0;
   virtual std::unique_ptr<AnyBase> clone() = 0;
};

template <typename T>class AnyWrapper : public AnyBase{public:
   explicit AnyWrapper(T value) : value_(std::move(value)){}
   std::type_index type() const override { //存儲(chǔ)了類型信息,類型轉(zhuǎn)換時(shí)用
       return typeid(T);
   }

   std::unique_ptr<AnyBase> clone() override{        return std::make_unique<AnyWrapper<T>>(value_);
   }
   T& get(){        return value_;
   }

private:
   T value_;
};class SimpleAny{public:
   SimpleAny() = default;

   template <typename T>
   SimpleAny(T value)
       : value_(std::make_unique<AnyWrapper<T>>(std::move(value))){}

   SimpleAny(const SimpleAny& other)
       : value_(other.value_ ? other.value_->clone() : nullptr){}
   
   SimpleAny& operator=(const SimpleAny& other) {        if (this != &other) {
           value_ = other.value_ ? other.value_->clone() : nullptr;
       }        return *this;
   }

   std::type_index type() const{        return value_ ? value_->type() : typeid(void);
   }

   template <typename T>
   T& get(){        if (type() != typeid(T)) { //類型轉(zhuǎn)換時(shí)判斷是否類型匹配
           throw std::bad_cast();
       }        return static_cast<AnyWrapper<T>*>(value_.get())->get();
   }private:
   std::unique_ptr<AnyBase> value_;
};

int main(){
   SimpleAny a(10);
   std::cout << "Stored int: " << a.get<int>() << "n";

   a = std::string("Hello, Any!");
   std::cout << "Stored string: " << a.get<std::string>() << "n";    return 0;
}

本例中,“SimpleAny”用于存儲(chǔ)一個(gè) int 類型,然后存儲(chǔ)一個(gè) std::string 類型。


關(guān)鍵詞: C++ 類型擦除

評(píng)論


技術(shù)專區(qū)

關(guān)閉