2010-07-21 15 views
9

ऐसे मामले हैं जब लाइब्रेरी स्रोत उपलब्ध होता है, और इसे सामान्य रूप से परिवर्तनीय पैरामीटर का समर्थन करना होता है, लेकिन व्यवहार में ये पैरामीटर आमतौर पर स्थिरांक होते हैं।सी ++ संकलन-समय निरंतर पहचान

फिर निरंतर पैरामीटर के विशेष संचालन द्वारा चीजों को अनुकूलित करना संभव हो सकता है (उदाहरण के लिए, ढेर आवंटन के बजाय स्थैतिक सरणी का उपयोग करें), लेकिन इसके लिए यह निर्धारित करना आवश्यक है कि कुछ स्थिर है (या शायद कुछ मैक्रोज़ को परिभाषित करें, लेकिन इसके कम सुविधाजनक)।

तो यहां एक कार्य कार्यान्वयन है।

अद्यतन: भी यहाँ: http://codepad.org/ngP7Kt1V

  1. यह वास्तव में एक वैध C++ है?
  2. क्या इन मैक्रोज़ से छुटकारा पाने का कोई तरीका है? (Is_const() एक समारोह क्योंकि समारोह निर्भरता सरणी आकार अभिव्यक्ति में काम नहीं करेगा नहीं किया जा सकता;। यह भी एक टेम्पलेट नहीं किया जा सकता है कि या तो एक चर पैरामीटर को स्वीकार नहीं करेगा क्योंकि)

अद्यतन: यहां इच्छित उपयोग की तरह कुछ और अपडेट है। कंपाइलर if(N==0) शाखा के लिए कोई कोड उत्पन्न नहीं करेगा यदि नहीं है, तो हम उसी तरह से अलग-अलग डेटा संरचनाओं पर स्विच कर सकते हैं। यकीन है कि यह सही नहीं है, लेकिन इसलिए मैंने यह प्रश्न पोस्ट किया है।


#include <stdio.h>

struct chkconst { struct Temp { Temp(int x) {} }; static char chk2(void*) { return 0; } static int chk2(Temp ) { return 0; } }; #define is_const_0(X) (sizeof(chkconst::chk2(X))<sizeof(int)) #define is_const_0i(X) (sizeof(chkconst::chk2(X))>sizeof(char)) #define is_const(X) is_const_0((X)^((X)&0x7FFFFFFF)) #define const_bit(X1,bit) (is_const_0i((X1)&(1<<bit))<<bit) #define const_nibl(X1,bit) const_bit(X1,bit) | const_bit(X1,(bit+1)) | const_bit(X1,(bit+2)) | const_bit(X1,(bit+3)) #define const_byte(X1,bit) const_nibl(X1,bit) | const_nibl(X1,(bit+4)) #define const_word(X1,bit) const_byte(X1,bit) | const_byte(X1,(bit+8)) #define const_uint(X1) const_word(X1,0) | const_word(X1,16) #define const_switch_word(X1, X2) (is_const(X1) ? const_word(X1,0) : X2) #define const_switch_uint(X1, X2) (is_const(X1) ? const_uint(X1) : X2) const int X1 = 222; const int X2 = printf("") + 333; char Y1[ const_switch_word(X1,256) ]; char Y2[ const_switch_word(X2,256) ]; template< int N > void test(int N1) { char _buf[N>0?N:1]; char* buf = _buf; if(N==0) { buf = new char[N1]; } printf("%08X %3i %3i\n", buf, N, N1); } #define testwrap(N) test< const_switch_word(N,0) >(N) int main(void) { printf("%i %i %i\n", X1, is_const(X1), sizeof(Y1)); printf("%i %i %i\n", X2, is_const(X2), sizeof(Y2)); testwrap(X1); testwrap(X2); }
+0

' is_const उदाहरण (एक परिणाम के संकलन समय अपरिभाषित कर) भी शामिल है 'is_const (एक्स) के साथ काम करता | is_const (-X) 'भी है, इस प्रकार केवल' all x: x! = INT_MIN' के लिए काम कर रहा है। –

+0

ध्यान दें कि 'आकार (int) 'और' sizeof (char) 'को अलग होने की गारंटी नहीं है (और वास्तविक जीवन प्रोसेसर हैं जहां वे समान हैं), इसलिए आपको' char [2]' जैसे कुछ का उपयोग करना चाहिए। (दूसरी ओर, मुझे हार्डकोडेड स्थिरांक दिखाई देते हैं, इसलिए मुझे लगता है कि पोर्टेबिलिटी चिंता का विषय नहीं है।) – ymett

+0

ग्रेट कोड, अच्छा विचार (मुझे लगता है कि मूल स्रोत http://encode.ru/threads/396-C-compile-time है -constant का पता लगाने?)। मैंने is_const कोड को कुछ और पोर्टेबल (आकार के चार मुद्दों, INT_MAX प्रयुक्त) के रूप में अनुकूलित किया है, सभी संभावित इनपुट मानों को संभालने के लिए, और एक सरल गैर-जीसीसी संस्करण बनाया - http://stackoverflow.com/questions/7658060/ देखें Can-i-use-assume-hint-to-elide-a-call-if-a-edge-condition-is-known-at-compile/7658363 # 7658363 – Suma

उत्तर

0

आप टेम्पलेट पैरामीटर तो यह एक constexpr (संकलन समय भाव के लिए मानक का कार्यकाल) होने की गारंटी है में पारित कर सकते हैं। यदि यह टेम्पलेट पैरामीटर द्वारा पारित नहीं किया गया है, तो यह एक constexpr नहीं है। इसके अलावा कोई रास्ता नहीं है।

ऑलोकै का उपयोग करके एक स्टैक आवंटित चर लंबाई लंबाई वर्ग को हाथ से रोल करना कितना आसान होगा। यह सरणी के लिए स्टैक आवंटन की गारंटी देगा, इस पर ध्यान दिए बिना कि वे स्थिर हैं या नहीं। इसके अलावा, आप वेक्टर/बूस्ट :: सरणी की समान पुनरावृत्ति कार्यक्षमता प्राप्त कर सकते हैं।

 #define MAKE_VLA(type, identifier, size) VLA< (type) > identifier (alloca((size) * sizeof (type)), (size)); 
     template<typename T> class VLA { 
      int count; 
      T* memory; 
      VLA(const VLA& other); 
     public: 
      // Types 
      typedef T* pointer; 
      typedef T& reference; 
      typedef const T* const_pointer; 
      typedef const T& const_reference; 
      typedef T value_type; 
      typedef std::size_t size_type; 
      class iterator { 
       mutable T* ptr; 
       iterator(T* newptr) 
        : ptr(newptr) {} 
      public: 
       iterator(const iterator& ref) 
        : ptr(ref.ptr) {} 

       operator pointer() { return ptr; } 
       operator const pointer() const { return ptr; } 

       reference operator*() { return *ptr; } 
       const reference operator*() const { return *ptr; } 

       pointer operator->() { return ptr; } 
       const pointer operator->() const { return ptr; } 

       iterator& operator=(const iterator& other) const { 
        ptr = iterator.ptr; 
       } 

       bool operator==(const iterator& other) { 
        return ptr == other.ptr; 
       } 
       bool operator!=(const iterator& other) { 
        return ptr != other.ptr; 
       } 

       iterator& operator++() const { 
        ptr++; 
        return *this; 
       } 
       iterator operator++(int) const { 
        iterator retval(ptr); 
        ptr++; 
        return retval; 
       } 
       iterator& operator--() const { 
        ptr--; 
        return *this; 
       } 
       iterator operator--(int) const { 
        iterator retval(ptr); 
        ptr--; 
        return retval; 
       } 

       iterator operator+(int x) const { 
        return iterator(&ptr[x]); 
       } 
       iterator operator-(int x) const { 
        return iterator(&ptr[-x]); 
       } 
      }; 
      typedef const iterator const_iterator; 
      class reverse_iterator { 
       mutable T* ptr; 
       reverse_iterator(T* newptr) 
        : ptr(newptr) {} 
      public: 
       reverse_iterator(const reverse_iterator& ref) 
        : ptr(ref.ptr) {} 

       operator pointer() { return ptr; } 
       operator const pointer() const { return ptr; } 

       reference operator*() { return *ptr; } 
       const reference operator*() const { return *ptr; } 

       pointer operator->() { return ptr; } 
       const pointer operator->() const { return ptr; } 

       reverse_iterator& operator=(const reverse_iterator& other) const { 
        ptr = reverse_iterator.ptr; 
       } 
       bool operator==(const reverse_iterator& other) { 
        return ptr == other.ptr; 
       } 
       bool operator!=(const reverse_iterator& other) { 
        return ptr != other.ptr; 
       } 

       reverse_iterator& operator++() const { 
        ptr--; 
        return *this; 
       } 
       reverse_iterator operator++(int) const { 
        reverse_iterator retval(ptr); 
        ptr--; 
        return retval; 
       } 
       reverse_iterator& operator--() const { 
        ptr++; 
        return *this; 
       } 
       reverse_iterator operator--(int) const { 
        reverse_iterator retval(ptr); 
        ptr++; 
        return retval; 
       } 

       reverse_iterator operator+(int x) const { 
        return reverse_iterator(&ptr[-x]); 
       } 
       reverse_iterator operator-(int x) const { 
        return reverse_iterator(&ptr[x]); 
       } 
      }; 
      typedef const reverse_iterator const_reverse_iterator; 
      typedef unsigned int difference_type; 

      // Functions 
      ~VLA() { 
       for(int i = 0; i < count; i++) 
        memory[i].~T(); 
      } 
      VLA(void* stackmemory, int size) 
       : memory((T*)stackmemory), count(size) { 
        for(int i = 0; i < count; i++) 
         new (&memory[i]) T(); 
      } 

      reference at(size_type pos) { 
       return (reference)memory[pos]; 
      } 
      const_reference at(size_type pos) { 
       return (const reference)memory[pos]; 
      } 
      reference back() { 
       return (reference)memory[count - 1]; 
      } 
      const_reference back() const { 
       return (const reference)memory[count - 1]; 
      } 

      iterator begin() { 
       return iterator(memory); 
      } 
      const_iterator begin() const { 
       return iterator(memory); 
      } 

      const_iterator cbegin() const { 
       return begin(); 
      } 

      const_iterator cend() const { 
       return end(); 
      } 

      const_reverse_iterator crbegin() const { 
       return rbegin(); 
      } 

      const_reverse_iterator crend() const { 
       return rend(); 
      } 

      pointer data() { 
       return memory; 
      } 
      const_pointer data() const { 
       return memory; 
      } 

      iterator end() { 
       return iterator(&memory[count]); 
      } 
      const_iterator end() const { 
       return iterator(&memory[count]); 
      } 

      reference front() { 
       return memory[0]; 
      } 
      const_reference front() const { 
       return memory[0]; 
      } 

      reverse_iterator rbegin() { 
       return reverse_iterator(&memory[count - 1]); 
      } 
      const_reverse_iterator rbegin() const { 
       return const_reverse_iterator(&memory[count - 1]); 
      } 
      reverse_iterator rend() { 
       return reverse_iterator(memory[-1]); 
      } 
      const_reverse_iterator rend() const { 
       return reverse_iterator(memory[-1]); 
      } 

      size_type size() { 
       return count; 
      } 

      reference operator[](int index) { 
       return memory[index]; 
      } 
      const reference operator[](int index) const { 
       return memory[index]; 
      } 
     }; 

ध्यान दें कि मैं वास्तव में इस कोड का परीक्षण नहीं किया है, लेकिन यह, हड़पने उपयोग करते हैं, और बनाए रखने की तुलना में अपने ओपी में है कि कुरूपता बनाए रखने के लिए करने के लिए बहुत आसान होता।

+0

ठीक है, मेरा कोड किसी फ़ंक्शन को पास करने का एक तरीका लागू करता है (संभव) चर टेम्पलेट पैरामीटर के रूप में चर। इसके अलावा यह वास्तव में ढेर पर तालिकाओं को आवंटित करने के बारे में नहीं है, लेकिन एक अनुकूलित लाइब्रेरी संस्करण में स्विच करने के बारे में जब ऐसा प्रतीत होता है कि (शायद कुछ) पैरामीटर संकलन समय पर ज्ञात हैं। – Shelwien

+0

@ शेल्वियन: यह सच है कि आपके कोड में कुछ संभावित क्षमता है जो मेरा नहीं है। हालांकि, मेरे कोड में भी बहुत संभावना है कि आपका नहीं है। – Puppy

+0

निश्चित रूप से, आपका कोड साझा करने के लिए धन्यवाद, लेकिन imho यह वास्तव में विषय से संबंधित नहीं है :) – Shelwien

1

is_const अधिक विश्वसनीय होना चाहिए। जीसीसी-4.4 उदाहरण के लिए पर, निम्नलिखित:

int k=0; 
printf("%d\n",is_const(k),is_const(k>0)); 

प्रिंट:

0,1 

जीसीसी काफी महत्वाकांक्षी तह निरंतर भाव जो मानक के शब्दों द्वारा अभिन्न निरंतर भाव नहीं हैं। is_const की एक संभावित बेहतर परिभाषा हो सकता है:

#define is_const(B)\ 
(sizeof(chkconst::chk2(0+!!(B))) != sizeof(chkconst::chk2(0+!(B)))) 
तरफ से

, अपने तकनीक भयानक है, क्योंकि मैं अंत में एक SUPER_ASSERT मैक्रो जो संकलन के दौरान चेक किया गया है लिख सकते हैं, तो दावे अभिव्यक्ति यदि संकलन समय और अन्यथा रनटाइम के दौरान :

#define SUPER_ASSERT(X) {BOOST_STATIC_ASSERT(const_switch_uint(X,1));assert(X);} 

मैं उस const_switch_xxx() चीज़ को बाद में देखूंगा।मुझे नहीं पता कि किसी अन्य तरीके को कैसे कार्यान्वित किया जाए, deconstruct/reconstruct trick शानदार है।

+1

द्वारा सचित्र है, क्या यह वास्तव में जीसीसी द्वारा मानक का उल्लंघन नहीं है? मुझे कोई भी शब्द नहीं मिल रहा है जो इसे समझने की अनुमति देगा। 'के-के' (जहां 'के' प्रकार' हस्ताक्षरित int' प्रकार का एक चर है) एक अभिन्न निरंतर अभिव्यक्ति के रूप में और इसलिए एक शून्य-सूचक स्थिरांक के रूप में, भले ही यह हमेशा शून्य का मूल्यांकन करता है। – jpalecek

+0

नोट: जैसा कि आप केवल संकलन समय शून्य का पता लगाने के बारे में चिंतित हैं, SUPER_ASSERT कार्यान्वयन बहुत आसान हो सकता है, बिना const_switch और किसी भी gcc संगतता समस्या: #Dfine SUPER_ASSERT (X) {BOOST_STATIC_ASSERT (! Is_const_0 (X)); जोर दें (एक्स) ;} – Suma

1

यदि आप जीसीसी के साथ काम कर रहे हैं, तो आपको यह बताने के लिए __builtin_constant_p का उपयोग करें कि कुछ संकलन समय स्थिर है या नहीं। प्रलेखन() `एक्स> = 0 केवल, फिर भी चाल के लिए काम करती

static const int table[] = { 
    __builtin_constant_p (EXPRESSION) ? (EXPRESSION) : -1, 
    /* ... */ 
}; 
+0

मैंने कोशिश की, लेकिन इसके अलग-अलग, समान बढ़ावा टेम्पलेट के समान ही - मेरा उदाहरण काम नहीं करता है अगर मैं is_const 0 को फिर से परिभाषित करता हूं और isinconstąi उस अंतर्निहित - const_switch * का उपयोग कर गलत है और टेम्पलेट उदाहरण संकलित नहीं होता है। इसके अलावा मुझे जीसीसी के बगल में एमएससी और इंटेलसी के साथ संगत होने की जरूरत है। – Shelwien

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