टेम्प्लेट गोलाकार अवलंबित्व - वेगवेगळ्या फाइल्समध्ये वेगळे वर्ग

सर्वप्रथम, मला असे म्हणायचे आहे की मला माहिती आहे की या प्रकारचा प्रश्न यापूर्वी विचारला गेला आहे (उदा. येथे टेम्पलेट वर्गांमधील परिपत्रक अवलंबित्व सोडवणे).

तथापि, हे समाधान (अंमलबजावणीपासून घोषणा वेगळे करणे) दोन्ही वर्ग एकाच फाईलमध्ये टाकल्यावरच कार्य करते. माझ्या बाबतीत, माझ्याकडे स्टेट मॅनेजर आणि स्टेट क्लास आहे जे दोन्ही बऱ्यापैकी मोठे आहेत आणि वाढण्याची हमी आहे. अशा प्रकारे ते एका मोठ्या फाईलमध्ये असणे माझ्यासाठी असमाधानकारक वाटते.

येथे काही महत्त्वाचे कोड स्निपेट्स आहेत:

// 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;
}

येथे RequestStackPush() पद्धतीची अंमलबजावणी आहे

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);
    }

अर्थात, StateManager सर्व वेळ State वर्ग वापरते. तो तयार करतो त्याला मेथड्स वगैरे म्हणतात. त्यामुळे फॉरवर्ड डिक्लेरेशन इथे उपाय नाही. फक्त तुम्हाला एक उदाहरण देण्यासाठी:

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));
    }

सध्या, दोन्ही वर्ग एकाच मोठ्या फाईलमध्ये आहेत. प्रथम, State वर्गाची घोषणा StateManager पुढे घोषित करून त्यानंतर StateManager वर्गाची घोषणा त्यानंतर वर वर्णन केलेल्या State::RequestStackPush() पद्धतीची अंमलबजावणी आणि शेवटी सर्व राज्यव्यवस्थापक टेम्पलेट पद्धतींची अंमलबजावणी.

मी हे दोन वेगवेगळ्या फायलींमध्ये कसे वेगळे करू शकतो?


person Adrian Albert Koch    schedule 14.12.2017    source स्रोत
comment
तुम्ही फक्त StateManager संदर्भ आणि RequestStackPush पद्धत काढून टाकण्याचा विचार केला आहे का? तुमच्या उर्वरित कोडसाठी ते किती वाईट असेल?   -  person Sebastian Redl    schedule 14.12.2017
comment
व्युत्पन्न राज्याला कोणताही डेटा पास करण्यास सक्षम असण्यासाठी ते महत्त्वपूर्ण असल्याने वाईट. पुश केलेल्या स्थितीच्या निर्मितीस विलंब करण्यासाठी विनंती स्टेट पुश आवश्यक आहे. स्टेट स्टॅक अपडेट करताना किंवा रेंडर करताना स्टेट तयार केल्याने त्रुटी येऊ शकतात   -  person Adrian Albert Koch    schedule 14.12.2017
comment
मला असे म्हणायचे होते की लोक StateManager::PushState थेट का वापरू शकत नाहीत?   -  person Sebastian Redl    schedule 14.12.2017
comment
@SebastianRedl, मी म्हटल्याप्रमाणे, हे अपडेट लूपमध्ये व्यत्यय आणू शकते किंवा प्रत्यक्षात राज्य स्टॅक लूप केले आहे.   -  person Adrian Albert Koch    schedule 14.12.2017


उत्तरे (1)


तथापि, हे समाधान (अंमलबजावणीपासून घोषणा वेगळे करणे) दोन्ही वर्ग एकाच फाईलमध्ये टाकल्यावरच कार्य करते.

नाही, हे फक्त एका फाईलमध्ये काम करत नाही. सब-हेडर समाविष्ट करून तुम्ही नेहमी एकसारखी फाइल तयार करू शकता. यासाठी तुम्हाला असे काहीतरी करणे आवश्यक आहे जे नॉन-टेम्प्लेट्ससह असामान्य असेल (जरी समान तंत्र सर्व इनलाइन फंक्शन व्याख्यांसह कार्य करते): वर्ग परिभाषित केल्यानंतर तुम्हाला फाइल समाविष्ट करणे आवश्यक आहे. हेडर्सना नाव असूनही फाईलच्या शीर्षस्थानी असण्यापुरते मर्यादित नाही.

तर, एका फाईलमध्ये:

  • घोषित करा StateManager
  • State परिभाषित करा
  • StateManager ची व्याख्या समाविष्ट करा
  • StateManager च्या व्याख्येवर अवलंबून असलेली सदस्य कार्ये परिभाषित करा

इतर फाईलमध्ये काहीही असामान्य नाही:

  • State ची व्याख्या समाविष्ट करा
  • StateManager आणि त्याची सदस्य कार्ये परिभाषित करा.

अंतिम परिणाम असा आहे की एकतर शीर्षलेख समाविष्ट करणे आवश्यक क्रमाने समान व्याख्या आणि घोषणा तयार करते. तर, फायलींचे हे विभाजन हेडरपैकी एक सुधारित केल्यामुळे पुन: संकलनाचे प्रमाण मर्यादित करण्यात कोणत्याही प्रकारे मदत करत नाही.

ही चवीची बाब असू शकते, परंतु मी नेहमी वर्गाच्या व्याख्येनंतर इनलाइन फंक्शन्स (टेम्प्लेट्स आणि टेम्पलेट फंक्शन्सच्या सदस्यांसह) आवश्यक असलेल्या व्याख्या समाविष्ट करतो. अशा प्रकारे असे करणे आवश्यक आहे की नाही याची मला काळजी करण्याची गरज नाही.

person eerorika    schedule 14.12.2017
comment
त्याला StateManager च्या व्याख्येपूर्वी State ची संपूर्ण व्याख्या आवश्यक आहे कारण काही फंक्शन स्वाक्षरी अंतर्गत प्रकारांचा संदर्भ घेतात. पण सर्वसाधारण कल्पना बरोबर आहे. - person Sebastian Redl; 14.12.2017
comment
@SebastianRedl आह, माझ्या लक्षात आले नाही की अवलंबित्व वादात आहे. फिक्सिंग... फिक्स्ड. - person eerorika; 14.12.2017
comment
@AdrianKoch State.h मध्ये State परिभाषित करण्यापूर्वी StateManager.h समाविष्ट करू नये. अन्यथा वर्तुळाकार अवलंबित्व आहे. आपण त्या समावेश लावतात करणे आवश्यक आहे. किमान पुनरुत्पादक उदाहरण शिवाय कसे हे सांगणे शक्य नाही. - person eerorika; 14.12.2017
comment
प्रत्येक चाइल्ड हेडरमध्ये तुम्ही वापरता येणारी दुसरी युक्ती म्हणजे पालक हेडर लोड केले गेले आहे, त्यामुळे तुमची ऑर्डर कायम ठेवली गेली आहे. मानक शीर्षलेख यासारख्या उदाहरणांनी भरलेले आहेत: #if !defined _MATH_H && !defined _COMPLEX_H # त्रुटी कधीही ‹bits/mathdef.h› थेट; #endif ऐवजी ‹math.h› समाविष्ट करा - person Gem Taylor; 14.12.2017