2011-11-29 10 views
5

मेरे पास बड़ी संख्या में कक्षाएं हैं जिनका उपयोग कुछ विशिष्ट तरीकों को सजाने के लिए किया जाता है।सजाने के तरीकों के दौरान बॉयलरप्लेट को कम करना

क्या बॉयलरप्लेट कोड (मुख्य रूप से सभी कन्स्ट्रक्टर पैरामीटर और सदस्यों को पकड़ने के लिए) को कम करने का कोई साफ तरीका है जिसे इन कक्षाओं में से प्रत्येक में जोड़ा जाना चाहिए? या, इससे भी बेहतर, क्या ऐसा करने का एक अच्छा तरीका है?

मैं वर्चुअल विधियों का उपयोग नहीं कर सकता, और केवल जीसीसी 4.6 और बनाम 2010 द्वारा समर्थित सी ++ 11 सुविधाओं के सबसेट का उपयोग कर सकता हूं।

मेरा मानना ​​है कि सी ++ 11 विरासत रचनाकार यहां मदद करेंगे, लेकिन न ही कंपाइलर उनका समर्थन करता है और मुझे कामकाज के बारे में पता नहीं है।

template<class Underlying, class T1> 
struct A : Base<A<Underlying, T1> > 
{ 
    typedef AImpl<decltype(declval<Underlying>().foo()), T1> impl; 
    A(Underlying u, T1 t1) : 
     u_(u), 
     t1_(t1) 
    {} 

    impl foo() const { return impl(u_.foo(), t1_); } 
    impl bar() const { return impl(u_.bar(), t1_); } 

    const Underlying u_; 
    T1 t1_; 
}; 


template<class Underlying, class T1, class T2> 
struct B : Base<B<Underlying, T1, T2> > 
{ 
    typedef BImpl<decltype(declval<Underlying>().bar()), T1, T2> impl; 
    B(Underlying u, T1 t1, T2 t2) : 
     u_(u), 
     t1_(t1), 
     t2_(t2) 
    {} 

    impl foo() const { return impl(u_.bar(), 999, t2_); } 
    impl bar() const { return impl(u_.foo(), t1_, t2_); } 

    const Underlying u_; 
    T1 t1_; 
    T2 t2; 
}; 

उत्तर

1

आप जीसीसी 4.6 में variadic टेम्पलेट का उपयोग कर सकते हैं:

यहाँ क्या इन कक्षाओं में वर्तमान की तरह लग रही का एक उदाहरण है।

template<class Underlying, class... T> 
struct B : Base<B<Underlying, T...>> 
{ 
    typedef BImpl<decltype(declval<Underlying>().bar()), T...> impl; 

    template<typename V...> 
    B(Underlying u, V... v) : 
     u_(u), 
     t_(std::forward<V>(v)...) 
    {} 

    impl foo() const { return impl(u_.bar(), 999, std::get<1>(t_)); } // Not sure what the 999 is? 
    impl bar() const { return impl(u_.foo(), std::get<0>(t_), std::get<1>(t_)); } 

    const Underlying u_; 
    std::tuple<T...> t_; 
}; 
+0

लेकिन वीसी ++ 2010 में नहीं ... – ildjarn

+0

मुझे लगता है कि 'आगे' का उपयोग थोड़ा गलत (कम से कम अक्षम) हो सकता है। डिफ़ॉल्ट रूप से, 'आगे' का कोई भी उपयोग घटाए गए पैरामीटर प्रकारों के साथ एक विधि कॉल में होना चाहिए। इसका मतलब है कि 'टेम्पलेट बी (अंतर्निहित यू, वी && ... टी): u_ (u), t_ (std :: आगे (टी) ...) {} '। तीन चीजें: 1) फ़ंक्शन स्वयं टेम्पलेट होना चाहिए। 2) तर्कों को 'यू एंड& ...' के रूप में लिया जाना चाहिए, और 'आगे' shuld का उपयोग किया जाना चाहिए। वर्तमान कोड * बी * में पैरामीटर * प्रतिलिपि * करेगा और फिर यह * उन्हें * बेस क्लास में ले जा सकता है। आदर्श रूप से, आप शून्य प्रतियां चाहते हैं और जब संभव हो, तो सभी तरह से आगे बढ़ते हैं। –

+1

दो चीजें, मानक कार्यान्वयन में टुपल का सदस्य नहीं है (यह बूस्ट में है), और आगे का उपयोग आपके कन्स्ट्रक्टर में गलत है। 'टेम्पलेट बी होना चाहिए (अंतर्निहित यू, वी && ... v): u_ (u), t_ (std :: आगे (v) ...) {}'। – DRayX

1

यदि इसे बनाम 2010 में काम करने की आवश्यकता है, तो आपकी सर्वश्रेष्ठ शर्त Boost.Preprocessor है। यह वैरिएडिक टेम्पलेट्स के रूप में मजबूत नहीं है जिसमें इसकी अधिकतम रिकर्सन गहराई 3 है और अधिकतम 256 की पुनरावृत्ति गणना है, लेकिन यह सी ++ 11 समर्थन के साथ या उसके बिना प्रत्येक कंपाइलर में काम करता है। यह पूरी तरह स्पष्ट नहीं है कि आप उन उदाहरणों के साथ क्या करने का प्रयास कर रहे हैं, लेकिन यदि आप केवल फ़ंक्शंस को सजाने की कोशिश कर रहे हैं, तो मैं निम्नलिखित का उपयोग करता हूं (भिन्नता वाले टेम्पलेट्स के बजाय Boost.Preprocessor के साथ पूर्ण अग्रेषण के लिए C++ 11 का उपयोग करता है):

#define FORWARD(z, n, data) \ 
    ::std::forward<BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 0, data), n)> \ 
    (BOOST_PP_CAT(BOST_PP_TUPLE_ELEM(2, 1, data), n)) \ 
    /**/ 

//------------------------------------------------------------------------ 
// template<class R, class... A> 
// ::std::function<R(A...)> decorate(::std::function<R(A...)> const& func) 
// { 
//  return [func](A&&... a) -> R 
//  { 
//   /* DECORATOR STUFF */ 
//   return func(::std::forward<A>(a)...); 
//  }; 
// } 
//------------------------------------------------------------------------ 
#define MACRO(z, n, _) \ 
    template<class R BOOST_PP_ENUM_TRAILING_PARAMS_Z(z, n, class A)> \ 
    ::std::function<R(BOOST_PP_ENUM_PARAMS_Z(z, n, a)> \ 
     decorate(::std::function<R(BOOST_PP_ENUM_PARAMS_Z(z, n, A))> const& func) \ 
    { \ 
     return [func](BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, A, &&a)) -> R \ 
     { \ 
      /* DECORATOR STUFF */ \ 
      return func(BOOST_PP_ENUM_ ## z(n, FORWARD, (A, a))); \ 
     }; \ 
    } \ 
    /**/ 

BOOST_PP_REPEAT(10, MACRO, ~) 

#undef MACRO 
#undef FORWARD 

यदि आप केवल फ़ंक्शन तर्कों को बांधने की कोशिश कर रहे हैं, तो std::bind वह है जिसे आप ढूंढ रहे हैं। ध्यान दें कि आप इनमें से lambdas के साथ ऐसा कर सकते हैं, लेकिन सजावटी कार्यों का उपयोग कई कार्यों को सजाने के लिए किया जा सकता है (जहां लैम्बडा निश्चित रूप से एक बंद होते हैं) और बांध बाध्यकारी तर्कों के लिए थोड़ा और संक्षिप्त हो सकता है (हालांकि, लैम्ब्डा समकक्ष कभी-कभी अधिक पठनीय होता है)।

संबंधित मुद्दे