九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
C 反射:全面解讀 property 的實(shí)現(xiàn)機(jī)制!

在上篇C++反射:深入淺出剖析ponder庫(kù)實(shí)現(xiàn)機(jī)制!中我們對(duì)反射實(shí)現(xiàn)的整體做了相關(guān)的介紹,本篇將深入Property的部分進(jìn)行介紹。

一、 Property示例代碼

//-------------------------------------//register code//-------------------------------------__register_type<Vector3>('Vector3') .constructor() .constructor<double, double, double>() .property('x', &Vector3::x) .property('y', &Vector3::y) .property('z', &Vector3::z) );
//-------------------------------------//use code//-------------------------------------auto* metaClass = __type_of<framework::math::Vector3>();ASSERT_TRUE(metaClass != nullptr);
auto obj = runtime::CreateWithArgs(*metaClass, Args{ 1.0, 2.0, 3.0 });ASSERT_TRUE(obj != UserObject::nothing);
const reflection::Property* fieldX = nullptr;metaClass->TryProperty('x', fieldX);ASSERT_TRUE(fieldX != nullptr);double x = fieldX->Get(obj).To<double>();ASSERT_DOUBLE_EQ(1.0, x);fieldX->Set(obj, 2.0);x = fieldX->Get(obj).to<double>();ASSERT_DOUBLE_EQ(2.0, x);

上面的代碼分為兩部分:

(一)注冊(cè)的代碼

注冊(cè)的代碼通過(guò)__register_type<T>()創(chuàng)建的ClassBuilder提供的。property(name,property)函數(shù)來(lái)完成對(duì)屬性的注冊(cè)。

(二)使用的代碼

使用的代碼,先獲取到MetaClass,再?gòu)腗etaClass中通過(guò)TryProperty()通過(guò)名字查詢到對(duì)應(yīng)的reflection::Property,然后我們可以通過(guò)Property的Get(),Set()方法來(lái)對(duì)對(duì)應(yīng)UserObject對(duì)象的屬性進(jìn)行設(shè)置和獲取。

(三)整體文章的展開思路

我們的講述會(huì)按照下面的順序逐步展開:

  • 一些基礎(chǔ)知識(shí)。

  • Property運(yùn)行時(shí)的承載對(duì)象Property類。

  • 編譯期的注冊(cè)機(jī)制。

  • 不同的Property特化實(shí)現(xiàn)。

  • 運(yùn)行時(shí)獲取值、設(shè)置值的具體過(guò)程。

二、基礎(chǔ)知識(shí)

C++中的Property多以Member Object的方式表達(dá),MemberObject的類型和處理方式比較特殊。以framework::math::Vector3舉例:

Vector3的成員變量定義如下:

class Vector3 { public:  double x;  double y;  double z;};

以下代碼是用來(lái)獲取成員變量y的:

//using MemberType = double(framework::math::Vector3::*);using MemberType = double framework::math::Vector3::*;MemberType tmppy = &framework::math::Vector3::y;framework::math::Vector3 tmpvec(1.0, 2.0, 3.0);auto tmpy = tmpvec.*tmppy;

簡(jiǎn)單總結(jié)如下:

  • 通過(guò)T(C::) 或者T C::來(lái)表達(dá)成員變量的類型,如上例中的 double(Framework::math::Vector3::) 。

  • 通過(guò)成員變量取地址的方式獲取對(duì)應(yīng)成員的地址,如上例中的&framework::math::Vector3::y。

  • 如上例中,可以通過(guò)tmpvec.tmppy這種獲取方式來(lái)獲取對(duì)應(yīng)對(duì)象中的成員(獲取的是tmpvec.y的值)。

  • 正常如果不是實(shí)現(xiàn)反射,很少使用相關(guān)的特性。

三、運(yùn)行時(shí)屬性的表達(dá)-Property類

為了實(shí)現(xiàn)運(yùn)行時(shí)Property,所有的Property需要進(jìn)行類型擦除,以一致的外觀進(jìn)行組織和調(diào)用,framework中的Property實(shí)現(xiàn)如下(節(jié)選):

class Property : public Type { public:  IdReturn name() const;
ValueKind kind() const;
virtual bool IsReadable() const;
virtual bool IsWritable() const;
Value Get(const UserObject& object) const;
void Set(const UserObject& object, const Value& value) const;
inline TypeId type_index() const { return type_index_; }
inline auto implement_type() const { return implement_type_; } protected: virtual Value GetValue(const UserObject& object) const = 0; virtual void SetValue(const UserObject& object, const Value& value) const = 0;};

主要使用的是Get(),Set()兩個(gè)方法,用于從UserObject中獲取和設(shè)置指定Property的值。

四、依賴的核心機(jī)制

雖然Property整體的機(jī)制比較復(fù)雜,但核心依賴的機(jī)制實(shí)現(xiàn)比較簡(jiǎn)潔,主要依賴的是ValueBinder<>和ValueBinder2<>,以及與這兩者基本一致的InternetRefBinder<>和InternetRefBinder2<>模板類。

(一)ValueBinder<>和ValueBinder2<>

ValueBinder<>的實(shí)現(xiàn)如下圖所示:

上圖中還有個(gè)依賴的Binding對(duì)象,具體的信息如下:

相關(guān)的Function和Member的Traits我們下文中會(huì)具體展開,本部分主要關(guān)注ValueBinder和兩個(gè)Traits內(nèi)部的TBinding模板類的實(shí)現(xiàn)。先從ValueBinder的具體代碼說(shuō)起:

template <class C, typename PropTraits>class ValueBinder { public:  using ClassType = C;  using AccessType = typename std::conditional<    PropTraits::kIsWritable,     typename PropTraits::AccessType&,     typename PropTraits::AccessType  >::type;    using SetType = typename std::remove_reference<AccessType>::type;  using Binding = typename PropTraits::template TBinding<ClassType, AccessType>;
ValueBinder(const Binding& b) : bound_(b) {} AccessType Getter(ClassType& c) const { return bound_.Access(c); } bool Setter(ClassType& c, SetType v) const { if constexpr (PropTraits::kIsWritable) return this->bound_.Access(c) = v, true; else return false; } bool Setter(ClassType& c, Value const& value) const { return Setter(c, value.to<SetType>()); } Value GetValue(ClassType& c) const { if constexpr (PropTraits::kIsWritable) return UserObject::MakeRef(Getter(c)); else return UserObject::MakeCopy(Getter(c)); } protected: Binding bound_;};

Getter(),Setter()的實(shí)現(xiàn)主要依托Traits內(nèi)的TBinding::Access()來(lái)實(shí)現(xiàn),也就是我們上圖中所貼出的TFunctionTraits<T>::TBinding和 TMemberTraits<T>::TBinding實(shí)現(xiàn),這樣在模板層面,我們就有了一個(gè)獲取和設(shè)置對(duì)象屬性的模板類了,當(dāng)然,真正將ValueBinder用起來(lái),我們還需要其他的模板設(shè)施,暫時(shí)我們先關(guān)注最核心的這部分。

除了ValueBinder外,反射庫(kù)也提供了ValueBinder2模板類,看實(shí)現(xiàn)可以發(fā)現(xiàn),主要是提供了外部額外提供一個(gè)函數(shù)來(lái)做Setter的機(jī)制:

template <class C, typename PropTraits>class ValueBinder2 : public ValueBinder<C, PropTraits> { using Base = ValueBinder<C, PropTraits>; public: template <typename S> ValueBinder2(const typename Base::Binding& g, S s) : Base(g), set_(s) {} bool Setter(typename Base::ClassType& c, typename Base::SetType v) const { return set_(c, v), true; } bool Setter(typename Base::ClassType& c, Value const& value) const { return Setter(c, value.to<typename Base::SetType>()); } protected: std::function<void(typename Base::ClassType&, typename Base::AccessType)> set_;};

(二)Internet RefBinder<>與Internet RefBinder2<>實(shí)現(xiàn)

與ValueBinder提供的接口完全一致,主要是為UserObject類型的對(duì)象服務(wù)的,此處不詳細(xì)贅述了。

(三)反射框架中類名后的數(shù)字

Propety部分相關(guān)的模板類,不少都有數(shù)字,如ValueBinder2<>,InternalRefBinder2<>,GetSet2<>等,都是兩個(gè)參數(shù)版本的property注冊(cè)使用的,一個(gè)參數(shù)指定getter,一個(gè)參數(shù)指定setter,setter。前面介紹ValueBinder2的時(shí)候也有說(shuō)到,ValueBinder2通過(guò)額外的function對(duì)象重載了Setter()接口。

五、屬性的注冊(cè)

ClassBuilder提供了兩個(gè)版本的property注冊(cè)函數(shù),第一個(gè)版本對(duì)應(yīng)的是一個(gè)accessor的版本:

template <typename T>template <typename F>ClassBuilder<T>& ClassBuilder<T>::property(IdRef name, F accessor) {  if (target_->properties_table_.find(name.data()) == target_->properties_table_.end()) {    return AddProperty(detail::PropertyFactory1<T, F>::Create(name, accessor));  } else {    current_type_ = const_cast<Property*>(&(target_->GetProperty(name)));    return *this;  }}

第二個(gè)版本對(duì)應(yīng)的是兩個(gè)accessor的版本:

template <typename T>template <typename F1, typename F2>ClassBuilder<T>& ClassBuilder<T>::property(IdRef name, F1 accessor1, F2 accessor2) { if (target_->properties_table_.find(name.data()) == target_->properties_table_.end()) { return AddProperty(detail::PropertyFactory2<T, F1, F2>::Create(name, accessor1, accessor2)); } else { current_type_ = const_cast<Property*>(&(target_->GetProperty(name))); return *this; }}

從上述的兩段代碼可以看到,直接負(fù)責(zé)創(chuàng)建Property的是模板類的Create函數(shù),PropertyFactory1<T,F(xiàn)>::Create()和PropertyFactory2<T, F1,F(xiàn)2>::Create(),下文中會(huì)具體展開相關(guān)的實(shí)現(xiàn)。

六、PropertyFactory1<T, F>

&PropertyFactory2<T, F1, F2>具體實(shí)現(xiàn)

先以PropertyFactory1<T,F(xiàn)>::Create的處理過(guò)程為例,來(lái)看一下整體Property的創(chuàng)建流程:

整體處理流程如下:

  • 根據(jù)C,T推導(dǎo)正確的Accessor和PropertyImpl,主要是利用GetSet1<>模板類。

  • 利用GetSet1<>模板類中定義的Access類型, 關(guān)聯(lián)正確的AccessTraits類型。

  • 利用AccessTraits類型中定義的Impl和ValueBinder類型正確的產(chǎn)生InterfaceType和Property的具體Impl類(如SimplePropertyImpl類)。

整個(gè)處理過(guò)程比較復(fù)雜,下文中將詳細(xì)展開相關(guān)的類。

PropertyFactory2<>的處理流程基本與PropertyFactory1<>的處理流程一致, 主要的區(qū)別在于PropertyFactory2創(chuàng)建的Property的Setter是通過(guò)F2來(lái)指定的, 不詳細(xì)細(xì)述了。

(一)PropertyFactor與GetSet<>模板類

通過(guò)上圖的關(guān)系, 我們也能很容易的看到PropertyFactory處理屬性的類別,主要是三類:

  • GetSet1<TFunctionTraits<T>>用來(lái)處理以單個(gè)Getter函數(shù)提供的屬性。

  • GetSet1<TMemberTaits<T>>用來(lái)處理以第3節(jié)中介紹的,直接用Member Object來(lái)表達(dá)的屬性。

  • GetSet2<>用于表達(dá)以兩個(gè)函數(shù)分別表達(dá)getter,setter的屬性。

這里涉及的TFunctionTraits,TMemberTratis的定義如下所示:

  • TFunctionTraits

中間利用了另外一個(gè)輔助的模板類TCallableDetails<T>,細(xì)節(jié)如下:

整個(gè)Function Traits主要是對(duì)各種不同函數(shù)類型的特化表達(dá),最后方便我們獲?。?/span>

  • ParamTypes: 參數(shù)類型列表。

  • ReturnType: 返回值類型。

  • FuncType: 函數(shù)類型。

  • DispatchType: 用于構(gòu)建std::function<>的模板參數(shù)。

  • FunctionCallTypes: 同ParamTypes。


  • TMemberTraits

(二)GetSet模板類的實(shí)現(xiàn)

GetSet1模板類的定義與GetSet2基本一致,除了GetSet2明確利用函數(shù)來(lái)表達(dá)getter,setter。

(三)AccessTratis<>模板類的實(shí)現(xiàn)

如上圖所示,AccessTraits的核心信息比較少,主要是以下幾項(xiàng):

  • kind: 屬性的類別,主要是兩類,MemberObject和Function。

  • using ValueBinder: GetSet1用到的屬性綁定類型。

  • using ValueBinder2: GetSet2用到的屬性綁定類型。

AccessTraits主要有以下幾類:

覆蓋了我們反射支持的所有屬性類型:

  • SimplePropertyImpl

  • EnumPropertyImpl

  • ArrayPropertyImpl

  • UserPropertyImpl

七、不同的Property特化實(shí)現(xiàn)

要實(shí)現(xiàn)運(yùn)行時(shí)Property特性,光有上述介紹的GetSet<>,AccesssTraits<>模板類是不夠的,我們需要通過(guò)具體的PropertyImpl來(lái)將相關(guān)的功能串聯(lián)起來(lái)。

(一)SimplePropertyImpl

template <typename A>class SimplePropertyImpl : public SimpleProperty { public:  SimplePropertyImpl(IdRef name, A accessor); protected:  bool IsReadable() const final;  bool IsWritable() const final;  Value GetValue(const UserObject& object) const final {      return Value{accessor_.interface_.Getter(object.get<typename A::ClassType>())};  }  void SetValue(const UserObject& object, const Value& value) const final {      if (!accessor_.interface_.Setter(object.Ref<typename A::ClassType>(), value.to<typename A::DataType>()))          PONDER_ERROR(ForbiddenWrite(name()));  } private:  A accessor_;  // Accessor used to access the actual C++ property};

如圖所示,以 SimplePropertyImpl<>為橋梁,將GetSet1<>,ValueBinder<>等模板類串聯(lián)到一起,完成了對(duì)一個(gè)具體的UserObject某個(gè)屬性進(jìn)行設(shè)置和獲取的功能實(shí)現(xiàn)(中間還有GetSet模板與AccessTraits模板的串接,上文中已經(jīng)交代,這里不再重復(fù)。

另外的幾個(gè)PropertyImpl,如EnumPropertyImpl,ArrayPropertyImpl,UserPropertyImpl與SimplePropertyImpl的實(shí)現(xiàn)大同小異,這里不一一展開了。

八、獲取值、設(shè)置值的具體過(guò)程

我們以最前面例子中獲取屬性值時(shí)的調(diào)用棧以實(shí)際運(yùn)行的例子來(lái)看一下整個(gè)運(yùn)行時(shí)獲取屬性值的過(guò)程:

調(diào)用棧不太方便分析, 我們適當(dāng)格式化方便分析, 我們從上圖中從外到內(nèi)的順序來(lái)具體看一下:

(一)Stack Level1

格式化后的調(diào)用棧:

//code 1:framework::reflection::detail::SimplePropertyImpl< framework::reflection::detail::GetSet1< framework::math::Vector3, framework::reflection::detail::TMemberTraits<double framework::math::Vector3::*> >>::GetValue(const framework::reflection::UserObject & object);

對(duì)應(yīng)的代碼截圖:

(二)Stack Level2

格式化后的調(diào)用棧:

//code 2:framework::reflection::detail::ValueBinder<    framework::math::Vector3,    framework::reflection::detail::TMemberTraits<        double framework::math::Vector3::*    >>::Getter(framework::math::Vector3 & c);

對(duì)應(yīng)的代碼截圖:

(三)Stack Level3

格式化后的調(diào)用棧:

//code 3:framework::reflection::detail::TMemberTraits< double framework::math::Vector3::*>::TBinding<framework::math::Vector3,double &>::Access(framework::math::Vector3 & c)

對(duì)應(yīng)的代碼截圖:

(四)小結(jié)

利用多個(gè)模板類的級(jí)聯(lián)和使用,我們最后通過(guò)SimplePropertyImpl<>完成了運(yùn)行時(shí)動(dòng)態(tài)獲取屬性的目的,設(shè)置的過(guò)程與獲取的過(guò)程基本一致,這里不重復(fù)展開了。

九、總結(jié)

通過(guò)多層模板的級(jí)聯(lián),我們完成了運(yùn)行時(shí)動(dòng)態(tài)獲取設(shè)置屬性的功能,另外因?yàn)檎w代碼多利用模板,通過(guò)最后一節(jié)的分析,我們也能發(fā)現(xiàn),整體的性能其實(shí)是比較高的,更多還是依賴模板自身的特性和Tag Dispatch來(lái)完成了相關(guān)的功能。同時(shí),也能發(fā)現(xiàn),如果僅依托c++17的特性,模板之間的關(guān)聯(lián)會(huì)比較弱,整體代碼的維護(hù)和理解會(huì)比較麻煩。后續(xù)我們考慮用c++20的concept重構(gòu)整個(gè)反射庫(kù),到時(shí)再額外輸出相關(guān)的文章了。

- EOF -

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Android框架層學(xué)習(xí)指導(dǎo)
C++11 靜態(tài)斷言(static
Vector類模板界面及其函數(shù)的實(shí)現(xiàn)
C 模板詳解(一)
C++ 模板基礎(chǔ)談 - C/C++ / C++ 語(yǔ)言
SFINAE
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服