2011-05-03 18 views
12

मेरे पास मेरे कोड में स्ट्रिंग टैग हैं जो संख्याओं में परिवर्तित हो जाते हैं और टैग-वैल्यू संरचना में मानों को खोजने के लिए उपयोग किए जाते हैं।सी ++ संकलन समय फ़ंक्शन निष्पादन

मैं कुछ इस तरह है:

void foo() 
{ 
    type value = search("SomeTag"); 
} 

कहाँ खोज इस तरह परिभाषित किया गया है: कि धर्मान्तरित

type search(const char* tag) 
{ 
    return internal_search(toNumber(tag)); 
} 

क्योंकि हर समय टैग संकलन समय पर स्थिर है मैं कॉल निकालना चाहते हैं खोज फ़ंक्शन से किसी नंबर पर टैग करें। मुझे पता है कि टेम्पलेट्स (http://en.wikipedia.org/wiki/Compile_time_function_execution) का उपयोग करके संकलन समय पर कुछ सरल कार्यों को निष्पादित करना संभव है, लेकिन मुझे नहीं पता कि कैसे एक शून्य समाप्त टर्मिंग स्ट्रिंग के माध्यम से पुन: प्रयास करें और टेम्पलेट में मध्यवर्ती मान रखें। क्या आप एक साधारण नमूना दे सकते हैं जो एक शून्य समाप्त स्ट्रिंग को पुन: सक्रिय करता है और चार्ज को सार्वजनिक चर में जोड़ता है?

+1

एक विकल्प के रूप में, हो सकता है 'toNumber' सभी टैग का एक नक्शा रख सकता है कि उसने देखा है, और उनके संख्यात्मक मूल्य, ताकि आपको प्रति टैग एक बार रूपांतरण लागत का भुगतान करना पड़े? यह संकलन समय पर मूल्यांकन करने के लिए टेम्पलेट भाषा का उपयोग करने के रूप में उतना कुशल नहीं है, लेकिन मैं शर्त लगाता हूं कि कोड इस तरह से बहुत अधिक पठनीय और रखरखाव योग्य होगा। – aroth

+1

टीटीबीओएमके आप संकलन समय पर तारों पर फिर से नहीं जा सकते हैं। – sbi

+0

@aroth मुझे लगता है कि toNumber फ़ंक्शन खोज से तेज़ है, भले ही मैं लॉग 2 खोज का उपयोग करूं। – Felics

उत्तर

4

आप संकलन समय पर स्ट्रिंग अक्षर पर काम नहीं कर सकते हैं, इसलिए आप जो चाहते हैं उसमें संभव नहीं है। हालांकि, अगर आप संकलन-समय पर इन तारों को संसाधित करने पर विचार कर रहे हैं, तो इसका मतलब है कि आप संकलन समय पर सभी तारों को जानते हैं, और इससे आप जो चाहते हैं उसे स्वीकार्य अनुमानों पर पहुंच सकते हैं।

आपके द्वारा दिखाए गए कोड का तात्पर्य है कि नंबर पीढ़ी (चलिए इसे एक हैश कहते हैं) जब भी कोई टैग की खोज करता है तो उसे बुलाया जाता है। इसे एक आमंत्रण में कम करना स्वीकार्य होगा? यदि हां, तो आप स्थिरांक को परिभाषित करने और तार के बजाय इन इस्तेमाल कर सकते हैं:

const int SomeTag  = toNumber("SomeTag"  ); 
const int SomeOtherTag = toNumber("SomeOtherTag"); 
const int YetAnotherTag = toNumber("YetAnotherTag"); 
// ... 

फिर, बस search(SomeTag) द्वारा search("SomeTag") की सभी आवृत्तियां बदलें।

अगर वहाँ जो मामले में एक मैक्रो मदद कर सकता है टैग की एक बड़ी संख्या है, ऊपर बहुत कठिन हो सकता है टाइपिंग, है:

#define DEFINE_TAG(Tag_) const int Tag_ = toNumber(#Tag_); 

DEFINE_TAG(SomeTag); 
DEFINE_TAG(SomeOtherTag); 
DEFINE_TAG(YetAnotherTag); 
// ... 

#undef DEFINE_TAG 
+0

यह एक अच्छा विचार हो सकता है क्योंकि यह enum से बड़ी समस्या हल करता है (मुझे सभी प्रोजेक्ट फ़ाइलों में हेडर शामिल करने की आवश्यकता नहीं है और जब भी मैं एक नया टैग जोड़ता हूं) और स्थानीय परिभाषाओं (टैग विवाद) से इसे पुन: संकलित करने की आवश्यकता नहीं होती है। यहां एकमात्र समस्या अलग-अलग फाइलों और लिंकर त्रुटियों में एक ही टैग का पुनर्वितरण है, लेकिन .. इसे कॉन्स्ट int के बजाय स्थिर कॉन्स int के साथ हल किया जा सकता है। धन्यवाद! – Felics

+1

तो क्या आप तारों का उपयोग कर रहे हैं क्योंकि आप हर जगह शामिल होने के लिए enum नहीं चाहते हैं? मुझे लगता है कि आप जानते हैं कि आप वास्तव में रन-टाइम सुरक्षा के लिए संकलन-समय प्रदर्शन का व्यापार कर रहे हैं? क्या यह वास्तव में इसके लायक है? पिछले मामलों में मैंने पिछले मामलों में मूल्य स्थान को तोड़ना था (आपके मामले में: 'enum' मान) स्वतंत्र हिस्सों में (आपको इसके बजाय' const int 'का उपयोग करना होगा) जो विभिन्न शीर्षकों में परिभाषित किया गया है। फिर आप केवल उस शीर्षलेख को शामिल करते हैं जिसमें आप रुचि रखते हैं, और अन्य शीर्षकों में परिवर्तनों से प्रभावित नहीं होते हैं। – sbi

12

ऐसा लगता है कि आप क्या चाहते हैं BoostMPL का boost::mpl::string। का उपयोग करके संकलन समय पर mpl::string को एक अभिन्न प्रकार में कनवर्ट करने के लिए मेटाफंक्शन लिखना अधिक कम या कम होगा (या स्ट्रिंग शब्दशः मान्य अभिन्न मान का प्रतिनिधित्व नहीं करता है तो संकलित करने में विफल)।

संपादित करें:

मैं पूरी तरह सुनिश्चित करें कि आप जो खोज रहे हैं, तो यहाँ नहीं हूँ प्रभावी रूप से दो अलग व्याख्या के आधार पर जवाब है:


यदि क्या आप 'की तलाश है संकलन-समय स्ट्रिंग-टू-इंटीग्रल-वैल्यू रूपांतरण (उदाहरण के लिए "425897" को अभिन्न स्थिरके रूप में पहचाना जा सकता है संकलन समय पर), फिर एक Boost.MPL के रूप में मैं सुझाव का उपयोग कर सकते हैं:

#include <cstddef> 
#include <boost/type_traits/is_integral.hpp> 
#include <boost/type_traits/is_same.hpp> 
#include <boost/type_traits/is_signed.hpp> 
#include <boost/mpl/and.hpp> 
#include <boost/mpl/assert.hpp> 
#include <boost/mpl/char.hpp> 
#include <boost/mpl/contains.hpp> 
#include <boost/mpl/end.hpp> 
#include <boost/mpl/eval_if.hpp> 
#include <boost/mpl/find_if.hpp> 
#include <boost/mpl/fold.hpp> 
#include <boost/mpl/front.hpp> 
#include <boost/mpl/identity.hpp> 
#include <boost/mpl/integral_c.hpp> 
#include <boost/mpl/minus.hpp> 
#include <boost/mpl/negate.hpp> 
#include <boost/mpl/next.hpp> 
#include <boost/mpl/not.hpp> 
#include <boost/mpl/pair.hpp> 
#include <boost/mpl/placeholders.hpp> 
#include <boost/mpl/plus.hpp> 
#include <boost/mpl/pop_front.hpp> 
#include <boost/mpl/push_back.hpp> 
#include <boost/mpl/reverse_fold.hpp> 
#include <boost/mpl/size_t.hpp> 
#include <boost/mpl/string.hpp> 
#include <boost/mpl/times.hpp> 
#include <boost/mpl/vector.hpp> 

namespace details 
{ 
    namespace mpl = boost::mpl; 

    typedef mpl::vector10< 
     mpl::char_<'0'>, mpl::char_<'1'>, mpl::char_<'2'>, mpl::char_<'3'>, 
     mpl::char_<'4'>, mpl::char_<'5'>, mpl::char_<'6'>, mpl::char_<'7'>, 
     mpl::char_<'8'>, mpl::char_<'9'> 
    > valid_chars_t; 

    template<typename IntegralT, typename PowerT> 
    struct power_of_10; 

    template<typename IntegralT, std::size_t Power> 
    struct power_of_10<IntegralT, mpl::size_t<Power> > : mpl::times< 
     power_of_10<IntegralT, mpl::size_t<Power - 1u> >, 
     mpl::integral_c<IntegralT, 10> 
    > { }; 

    template<typename IntegralT> 
    struct power_of_10<IntegralT, mpl::size_t<1u> > 
     : mpl::integral_c<IntegralT, 10> 
    { }; 

    template<typename IntegralT> 
    struct power_of_10<IntegralT, mpl::size_t<0u> > 
     : mpl::integral_c<IntegralT, 1> 
    { }; 

    template<typename IntegralT, typename StringT> 
    struct is_negative : mpl::and_< 
     boost::is_signed<IntegralT>, 
     boost::is_same< 
      typename mpl::front<StringT>::type, 
      mpl::char_<'-'> 
     > 
    > { }; 

    template<typename IntegralT, typename StringT> 
    struct extract_actual_string : mpl::eval_if< 
     is_negative<IntegralT, StringT>, 
     mpl::pop_front<StringT>, 
     mpl::identity<StringT> 
    > { }; 

    template<typename ExtractedStringT> 
    struct check_valid_characters : boost::is_same< 
     typename mpl::find_if< 
      ExtractedStringT, 
      mpl::not_<mpl::contains<valid_chars_t, mpl::_> > 
     >::type, 
     typename mpl::end<ExtractedStringT>::type 
    > { }; 

    template<typename ExtractedStringT> 
    struct pair_digit_with_power : mpl::first< 
     typename mpl::reverse_fold< 
      ExtractedStringT, 
      mpl::pair<mpl::vector0<>, mpl::size_t<0> >, 
      mpl::pair< 
       mpl::push_back< 
        mpl::first<mpl::_1>, 
        mpl::pair<mpl::_2, mpl::second<mpl::_1> > 
       >, 
       mpl::next<mpl::second<mpl::_1> > 
      > 
     >::type 
    > { }; 

    template<typename IntegralT, typename ExtractedStringT> 
    struct accumulate_digits : mpl::fold< 
     typename pair_digit_with_power<ExtractedStringT>::type, 
     mpl::integral_c<IntegralT, 0>, 
     mpl::plus< 
      mpl::_1, 
      mpl::times< 
       mpl::minus<mpl::first<mpl::_2>, mpl::char_<'0'> >, 
       power_of_10<IntegralT, mpl::second<mpl::_2> > 
      > 
     > 
    > { }; 

    template<typename IntegralT, typename StringT> 
    class string_to_integral_impl 
    { 
     BOOST_MPL_ASSERT((boost::is_integral<IntegralT>)); 

     typedef typename extract_actual_string< 
      IntegralT, 
      StringT 
     >::type ExtractedStringT; 
     BOOST_MPL_ASSERT((check_valid_characters<ExtractedStringT>)); 

     typedef typename accumulate_digits< 
      IntegralT, 
      ExtractedStringT 
     >::type ValueT; 

    public: 
     typedef typename mpl::eval_if< 
      is_negative<IntegralT, StringT>, 
      mpl::negate<ValueT>, 
      mpl::identity<ValueT> 
     >::type type; 
    }; 
} 

template<typename IntegralT, typename StringT> 
struct string_to_integral2 
    : details::string_to_integral_impl<IntegralT, StringT>::type 
{ }; 

template<typename IntegralT, int C0, int C1 = 0, int C2 = 0, 
    int C3 = 0, int C4 = 0, int C5 = 0, int C6 = 0, int C7 = 0> 
struct string_to_integral : string_to_integral2< 
    IntegralT, 
    boost::mpl::string<C0, C1, C2, C3, C4, C5, C6, C7> 
> { }; 

प्रयोग दिखाई देगा:

type search(int tag) { /*impl... */ } 

void foo() 
{ 
    type value = search(string_to_integral<int, '4258','97'>::value); 
} 

// OR, if you still want to maintain the separation 
// between `search` and `internal_search` 

type internal_search(int tag) { /*impl... */ } 

template<typename TagStringT> 
type search() 
{ 
    return internal_search(string_to_integral2<int, TagStringT>::value); 
} 

void foo() 
{ 
    typedef boost::mpl::string<'4258','97'> tag_t; 
    type value = search<tag_t>(); 
} 

ऋणात्मक संख्याओं के लिए समर्थन कार्यान्वित किया जाता है, अतिप्रवाह का पता लगाने के लिए समर्थन नहीं है (लेकिन आपका कंपाइलर शायद एक चेतावनी देगा)।


यदि क्या आप देख रहे हैं संकलन समय स्ट्रिंग-से-अभिन्न-मूल्य मानचित्रण (जैसे इतना "SomeTag" अभिन्न निरंतर 425897 संकलन समय पर के रूप में पहचाना जा सकता है), तो है Boost.MPL अभी भी समस्या का हल है, लेकिन सभी स्ट्रिंग-से-अभिन्न-मूल्य मैपिंग संकलन समय पर जाना जाता है और केन्द्र में पंजीकृत होना जरूरी है:

0:

#include <boost/type_traits/is_same.hpp> 
#include <boost/mpl/assert.hpp> 
#include <boost/mpl/at.hpp> 
#include <boost/mpl/integral_c.hpp> 
#include <boost/mpl/map.hpp> 
#include <boost/mpl/pair.hpp> 
#include <boost/mpl/string.hpp> 
#include <boost/mpl/void.hpp> 

namespace details 
{ 
    namespace mpl = boost::mpl; 

    typedef mpl::map< 
     mpl::pair< 
      mpl::string<'Some','Tag'>, 
      mpl::integral_c<int, 425897> 
     >, 
     mpl::pair< 
      mpl::string<'Some','Othe','rTag'>, 
      mpl::integral_c<int, -87> 
     >, 
     mpl::pair< 
      mpl::string<'AnUn','sign','edTa','g'>, 
      mpl::integral_c<unsigned, 7u> 
     > 
    > mappings_t; 

    template<typename StringT> 
    struct map_string_impl 
    { 
     typedef typename mpl::at< 
      mappings_t, 
      StringT 
     >::type type; 
     BOOST_MPL_ASSERT_NOT((boost::is_same<type, mpl::void_>)); 
    }; 
} 

template<typename StringT> 
struct map_string2 : details::map_string_impl<StringT>::type { }; 

template<int C0, int C1 = 0, int C2 = 0, int C3 = 0, 
    int C4 = 0, int C5 = 0, int C6 = 0, int C7 = 0> 
struct map_string : map_string2< 
    boost::mpl::string<C0, C1, C2, C3, C4, C5, C6, C7> 
> { }; 

प्रयोग कैसा लगेगा

type search(int tag) { /*impl... */ } 

void foo() 
{ 
    type value = search(map_string<'Some','Tag'>::value); 
} 

// OR, if you still want to maintain the separation 
// between `search` and `internal_search` 

type internal_search(int tag) { /*impl... */ } 

template<typename TagStringT> 
type search() 
{ 
    return internal_search(map_string2<TagStringT>::value); 
} 

void foo() 
{ 
    typedef boost::mpl::string<'Some','Tag'> tag_t; 
    type value = search<tag_t>(); 
} 

mappings_t क्या मैप किया अभिन्न मान सभी एक ही अंतर्निहित प्रकार का होना नहीं की जरूरत के रूप में प्रदर्शित अपने स्ट्रिंग-से-अभिन्न-मूल्य मैपिंग बनाए रखने के लिए संपादित करने के लिए, और, की जरूरत है।


या तो मामले में, क्योंकि मानचित्रण संकलन समय पर किया जाता है, search/internal_search (एक int लेने वास्तविक कार्यान्वयन के साथ एक) टेम्पलेट पैरामीटर के रूप में के बजाय एक के रूप में अभिन्न मूल्य लेने के लिए किया जा सकता है ऐसा करने पर फ़ंक्शन पैरामीटर इसके कार्यान्वयन के लिए समझ में आता है।

उम्मीद है कि यह आपके प्रश्नों का उत्तर देगा।

+0

मैं कहता हूं कि यह छोटा नहीं है (कम से कम मेरे लिए नहीं), लेकिन यह किया जा सकता है। –

+0

कृपया मुझे एक कार्यान्वयन दें। यह सबसे अधिक वोट दिया गया जवाब है, लेकिन मुझे लगता है कि ऐसा करना संभव नहीं है, जैसा कि अन्य ने कहा था। जब मैं पूरा जवाब दूंगा तो मैं वोट दूंगा। – Felics

+1

@ फ़ेलिक्स: पूर्ण कार्यान्वयन के साथ संपादित। मैंने दो दृष्टिकोण दिए, क्योंकि यह मुझे स्पष्ट नहीं है कि आप वास्तव में क्या देख रहे हैं ... – ildjarn

0

अलथ्रू समय संकलित नहीं करता है, मुझे लगता है कि यह आपके लिए पर्याप्त तेज़ है;

void foo() 
{ 
    const static auto someTagN = toNumber("SomeTag"); 
    type value = internal_search(someTagN); 
} 
+0

यह संकलन समय पर नहीं चलेगा, बल्कि वैश्विक निर्माण समय पर, इसलिए यह कार्यक्रम स्टार्टअप को बढ़ाएगा। –

+0

यह वही है जो मैं टालना चाहता हूं, रन टाइम पर स्ट्रिंग रूपांतरण। मेरे पास कुछ टैग नहीं हैं जिनका उपयोग कई बार किया जाता है, मेरे पास अलग-अलग टैग होते हैं जिनका उपयोग केवल एक या कुछ बार किया जाता है। – Felics

+0

ठीक है तो इसे अनदेखा करें =) –

0

मुझे पता है कि यह शायद फैशनेबल नहीं है, लेकिन आप समय से पहले हैश-टेबल उत्पन्न कर सकते हैं। मैं वहां नलसाजी उत्पन्न करने के लिए gperf का उपयोग करना पसंद करता हूं।

मुझे पता है। आप कुछ देर तक संकलन करना चाहते थे ... बस कह रहे हैं :)

+0

यह कोई समस्या नहीं है, डीबग के लिए यह # परिभाषित एक्स (टैग) से संख्या (टैग) और रिलीज के लिए # परिभाषित एक्स (टैग) कुछ टेम्पलेट :: संख्या हो सकती है। यह रन टाइम अनुकूलन के लिए है, और संकलन समय अप्रासंगिक है। – Felics

+0

मैं आधा मजाक कर रहा था, मैं संकलन समय के बारे में चिंतित नहीं हूं :) – sehe

+0

संकलन समय एक बड़ी समस्या है। मेरे वर्तमान प्रोजेक्ट में एक पूर्ण पुनर्निर्माण में कई घंटे लग सकते हैं, और यह एक बहुत बड़ी समस्या है :) – Felics

0

सुनिश्चित नहीं है कि आप कर सकते हैं। संभावित टैग की सूची छोटी है? यहां तक ​​कि यदि नहीं, तो यह ज्यादातर समय छोटा है। यदि हां, तो आप टैग

template<char *tag> 
int toNumber() { 
    return toNumber(tag); 
} 

template<> 
int toNumber<"0">() { 
    return 0; 
} 

template<> 
int toNumber<"1">() { 
    return 1; 
} 

के एक उपसमूह पर टेम्पलेट विशेषज्ञता का उपयोग कर सकते (चेतावनियां: मेरे विशेषज्ञता वाक्य रचना गलत हो सकता है, और मैं पता नहीं अगर यह चार * के लिए काम करता है)

+2

टेम्पलेट चरित्र अक्षर, केवल स्थिरांक के पते स्वीकार नहीं करते हैं। तो आपको तारों के लिए 'कॉन्स्ट char * const' चर बनाना होगा और उन स्थिरांक को टेम्पलेट्स में पास करना होगा। –

+1

स्ट्रिंग अक्षर लिवल हैं और परिणामस्वरूप संकलन-समय स्थिरांक नहीं हो सकते हैं। हालांकि, * चरित्र * अक्षर वास्तव में संकलन-समय स्थिरांक हो सकते हैं। – ildjarn

2

स्ट्रिंग हैं शाब्दिक संकलन समय पर जाना जाता है, तो शायद स्ट्रिंग अक्षर के रूप में इसका उपयोग करने का कोई कारण नहीं है। आप गणना या नामित अभिन्न स्थिरांक का उपयोग कर सकते हैं।

यदि स्ट्रिंग को एक चर द्वारा खोज फ़ंक्शन में पास किया गया है और यह संकलन समय पर ज्ञात नहीं है, तो संकलन समय पर toNumber() पुनर्वसन करने का कोई तरीका नहीं है। फिर एक अच्छा समाधान किसी प्रकार का एक शब्दकोश का उपयोग करना है (उदा। std::map<std::string, int>)

+0

जैसा कि मैंने पहले कहा था, NNumber फ़ंक्शन खोज से तेज़ है। – Felics

+0

मुझे लगता है कि यहां पहला अनुच्छेद कुंजी है। संकलन समय पर ऐसा करने के लिए, आपको संकलन-समय पर सभी संभावित तारों को जानना होगा। और जब आपके पास, उनके लिए प्रतीकात्मक स्थिरांक का उपयोग न करने का कोई कारण नहीं है। – sbi

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