Şablon dairəvi asılılığı - müxtəlif fayllarda ayrı siniflər

hər şeydən əvvəl demək istəyirəm ki, bu cür sualın əvvəllər də verildiyini bilirəm (məsələn, burada Şablon Sinfləri Arasında Dairəvi Asılılığın Həlli Edilməsi).

Bununla belə, bu həll (bəyannaməni icradan ayırmaq) yalnız hər iki sinfi bir fayla yerləşdirərkən işləyir. Mənim vəziyyətimdə, hər ikisi kifayət qədər böyük və böyüməyə zəmanət verən bir StateManager və Dövlət sinifinə sahibəm. Beləliklə, onların bir böyük faylda olması mənim üçün qeyri-qənaətbəxş görünür.

Burada bəzi vacib kod parçaları:

// Forward declare the StateManager --> does not work (incomplete type)
class State
{
public:
    template <class TData>
    void RequestStackPush(ID stateId, std::shared_ptr<TData> data);
private:
    StateManager & stataManager;
}

Burada RequestStackPush() metodunun həyata keçirilməsi

template<class TData>
    inline void State::RequestStackPush(ID stateId, std::shared_ptr<TData> data)
    {
        // Uses the state manager's PushState() method - here the issue with the incomplete type arises
        stateManager.PushState<TData>(stateId, data);
    }

Aydındır ki, StateManager həmişə State sinifindən istifadə edir. Bu, metodları çağırır və s. yaradır, buna görə irəli bəyannamə burada heç bir həll yolu deyil. Sadəcə sizə bir misal çəkmək üçün:

template<class TData>
    inline void StateManager::PushState(State::ID stateId, std::shared_ptr<TData> data)
    {
        std::unique_ptr<BasePendingChange> pendingChange = std::make_unique<PendingPushDataChange<TData>>(Push, stateId, data);
        pendingChangeQueue.push(std::move(pendingChange));
    }

Hazırda hər iki sinif bir böyük fayldadır. Birincisi, StateManager ilə State sinifinin elanı, ardınca StateManager sinifinin elanı, ardınca yuxarıda təsvir edilən State::RequestStackPush() metodunun tətbiqi və nəhayət, bütün StateManager şablon metodlarının həyata keçirilməsi.

Bunu iki fərqli fayla necə ayıra bilərəm?


person Adrian Albert Koch    schedule 14.12.2017    source mənbə
comment
StateManager istinad və RequestStackPush metodunu sadəcə silməyi düşünmüsünüz? Bu, kodunuzun qalan hissəsi üçün nə qədər pis olardı?   -  person Sebastian Redl    schedule 14.12.2017
comment
Hər hansı bir məlumatı əldə edilmiş bir dövlətə ötürmək üçün çox vacib olduğundan pisdir. Sorğu Dövləti Push, itələnmiş vəziyyətin yaradılmasını gecikdirmək üçün lazımdır. Vəziyyət yığınını yeniləyərkən və ya göstərərkən vəziyyətin yaradılması xətalara səbəb ola bilər   -  person Adrian Albert Koch    schedule 14.12.2017
comment
Demək istəyirəm ki, insanlar niyə birbaşa StateManager::PushState-dən istifadə edə bilmirlər?   -  person Sebastian Redl    schedule 14.12.2017
comment
@SebastianRedl Dediyim kimi, bu, dövlət yığınının dövrələndiyi yeniləmə dövrəsini kəsə bilər və ya faktiki olaraq dayandıra bilər.   -  person Adrian Albert Koch    schedule 14.12.2017


Cavablar (1)


Bununla belə, bu həll (bəyannaməni icradan ayırmaq) yalnız hər iki sinfi bir fayla yerləşdirərkən işləyir.

Xeyr, o, yalnız bir faylda işləmir. Siz həmişə alt başlıqları daxil etməklə eyni faylı yarada bilərsiniz. Bu, sadəcə olaraq qeyri-şablonlarla qeyri-adi olacaq bir şey etməyinizi tələb edir (baxmayaraq ki, eyni texnika bütün daxili funksiya tərifləri ilə işləyir): Sinfi təyin etdikdən sonra fayl daxil etməlisiniz. Başlıqlar onlara verilən ada baxmayaraq faylın yuxarısında olmaqla məhdudlaşmır.

Beləliklə, bir faylda:

  • StateManager elan edin
  • State təyin edin
  • StateManager tərifini daxil edin
  • StateManager tərifindən asılı olan üzv funksiyalarını təyin edin

Digər faylda qeyri-adi heç nə yoxdur:

  • State tərifini daxil edin
  • StateManager və onun üzv funksiyalarını təyin edin.

Son nəticə ondan ibarətdir ki, hər iki başlığın daxil edilməsi tələb olunan qaydada eyni təriflər və bəyannamələr yaradır. Beləliklə, faylların bu şəkildə bölünməsi heç bir şəkildə başlıqlardan birinin dəyişdirilməsi nəticəsində yaranan təkrar kompilyasiya miqdarını məhdudlaşdırmağa kömək etmir.

Zövq məsələsi ola bilər, lakin mən həmişə sinifin tərifindən sonra daxili funksiyalar (o cümlədən şablonların üzvləri və şablon funksiyaları) tərəfindən tələb olunan tərifləri daxil edirəm. Beləliklə, bunu etmək lazım olub-olmamasından narahat olmaq lazım deyil.

person eerorika    schedule 14.12.2017
comment
O, StateManager tərifindən əvvəl State-in tam tərifinə ehtiyac duyur, çünki bəzi funksiya imzaları daxili tiplərə istinad edir. Amma ümumi fikir doğrudur. - person Sebastian Redl; 14.12.2017
comment
@SebastianRedl ah, asılılığın mübahisədə olduğunu görmədim. Təmir edilir... Düzəltildi. - person eerorika; 14.12.2017
comment
@AdrianKoch State.h State təyin edilməmişdən əvvəl StateManager.h daxil olmamalıdır. Əks halda dairəvi asılılıq yaranır. Bu daxil olmaqdan xilas olmalısınız. minimum təkrarlana bilən nümunə olmadan necə olacağını söyləmək mümkün deyil. - person eerorika; 14.12.2017
comment
Hər bir uşaq başlığında istifadə edə biləcəyiniz digər hiylə, ana başlığın yükləndiyini iddia etməkdir, buna görə də sifarişiniz qorunub saxlanılmışdır. Standart başlıqlar belə nümunələrlə doludur: #if !defined _MATH_H && !defined _COMPLEX_H # error Heç vaxt ‹bits/mathdef.h›-dan birbaşa istifadə etməyin; #endif yerinə ‹math.h› daxil edin - person Gem Taylor; 14.12.2017