2012-11-12 35 views
177

क्या निम्न परिभाषाओं के बीच कोई अंतर है?चर पर बनाम constexpr

const  double PI = 3.141592653589793; 
constexpr double PI = 3.141592653589793; 

यदि नहीं, तो सी ++ 11 में कौन सी शैली को प्राथमिकता दी जाती है?

+2

Superset: http://stackoverflow.com/questions/14116003/difference-between-constexpr-and-const –

उत्तर

197
के निष्पादन के समय धीमा नहीं होता

मुझे विश्वास है कि एक अंतर है। उन्हें इसलिए है कि हम उनके बारे में और अधिक आसानी से बात कर सकते हैं का नाम बदलने करते हैं:

const  double PI1 = 3.141592653589793; 
constexpr double PI2 = 3.141592653589793; 

दोनों PI1 और PI2 लगातार कर रहे हैं, जिसका अर्थ है कि आप उन्हें बदल नहीं सकते। हालांकि केवलPI2 एक संकलन-समय स्थिर है। यह संकलित समय पर आरंभ किया जाएगा। संकलन समय या रन टाइम पर PI1 प्रारंभ किया जा सकता है। इसके अलावा, केवलPI2 किसी संदर्भ में उपयोग किया जा सकता है जिसके लिए एक संकलन-समय निरंतर आवश्यकता होती है।

constexpr double PI3 = PI1; // error 

लेकिन:

constexpr double PI3 = PI2; // ok 

और:

static_assert(PI1 == 3.141592653589793, ""); // error 

लेकिन उदाहरण के लिए:

static_assert(PI2 == 3.141592653589793, ""); // ok 

के रूप में आप का उपयोग करना चाहिए जो करने के लिए? जो भी आपकी जरूरतों को पूरा करता है उसका प्रयोग करें। क्या आप यह सुनिश्चित करना चाहते हैं कि आपके पास एक संकलन समय निरंतर है जिसका उपयोग उन संदर्भों में किया जा सकता है जहां संकलन-समय निरंतर आवश्यकता होती है? क्या आप रन टाइम पर किए गए गणना के साथ इसे आरंभ करने में सक्षम होना चाहते हैं? आदि

+39

क्या आप निश्चित हैं? क्योंकि 'कॉन्स int एन = 10; चार ए [एन]; 'काम करता है, और सरणी सीमाएं संकलन-समय स्थिरांक होना चाहिए। – fredoverflow

+9

मुझे यकीन है कि जहां तक ​​मैंने लिखा उदाहरण पढ़ा है (पोस्ट करने से पहले उनमें से प्रत्येक का परीक्षण किया गया है)। हालांकि मेरे कंपाइलर ने मुझे 'पीआई 1' को एक सरणी में उपयोग के लिए एक संकलन-समय अभिन्न स्थिरांक में परिवर्तित करने दिया है, लेकिन गैर-प्रकार अभिन्न टेम्पलेट पैरामीटर के रूप में उपयोग के लिए नहीं। तो 'पीआई 1' की संकलन-समय परिवर्तनीयता को एक अभिन्न प्रकार में थोड़ा हिट लगता है और मुझे याद आती है। –

+0

@ हावर्ड हिन्नेंट: लैवल्यू-टू-रावल्यू रूपांतरण के नियम अभिन्न और गैर-अभिन्न प्रकारों के लिए अलग-अलग हैं: (5.1 9 (2)) 'अभिन्न या गणना प्रकार का एक ग्लैवल्यू जो एक पूर्व-अस्थिर कॉन्स ऑब्जेक्ट को संदर्भित करता है प्रारंभिक अभिव्यक्ति 'बनाम' के साथ प्रारंभिक अभिव्यक्ति 'बनाम' का प्रारंभिक प्रकार जो कि गैर-अस्थिर वस्तु को संदर्भित करता है जो कि कंस्ट्रैक्स के साथ परिभाषित किया गया है, या जो इस तरह के ऑब्जेक्ट के उप-ऑब्जेक्ट को संदर्भित करता है। यह 'int' में अंतर्निहित रूपांतरण के समान नहीं है, जिसमें अलग-अलग नियम हैं। – rici

58

यहां कोई अंतर नहीं है, लेकिन यह महत्वपूर्ण है जब आपके पास एक ऐसा प्रकार है जिसमें एक निर्माता है।

struct S { 
    constexpr S(int); 
}; 

const S s0(0); 
constexpr S s1(1); 

s0 एक निरंतर है, लेकिन यह संकलन समय पर प्रारंभ करने के लिए वादा नहीं करता। s1 को constexpr चिह्नित किया गया है, इसलिए यह स्थिर है और, क्योंकि S के निर्माता को भी constexpr चिह्नित किया गया है, यह संकलन समय पर शुरू किया जाएगा।

ज्यादातर यह मायने रखती है जब रनटाइम पर प्रारंभ समय लेने वाली हो सकता है और आप संकलक, जहां यह भी समय लेने वाली है पर है कि काम बंद पुश करने के लिए चाहते हैं, लेकिन संकलित कार्यक्रम

+3

मैं मानता हूँ: निष्कर्ष मैं के लिए पहुंचे कि 'constexpr' एक निदान करने के लिए नेतृत्व करेंगे चाहिए संकलन था वस्तु का समय गणना असंभव हो सकती है। कम स्पष्टता यह है कि क्या एक फ़ंक्शन * अपेक्षित * स्थिर पैरामीटर को संकलित समय पर निष्पादित किया जा सकता है, पैरामीटर को 'const' के रूप में घोषित किया जाना चाहिए, न कि 'constexpr' के रूप में: यानी,' constexpr int foo (S)' निष्पादित किया जाएगा संकलन समय पर अगर मैं 'foo (s0)' कहता हूं? –

+4

@MatthieuM: मुझे संदेह है कि 'foo (s0) 'संकलन समय पर निष्पादित किया जाएगा, लेकिन आप कभी नहीं जानते: एक कंपाइलर को ऐसे अनुकूलन करने की अनुमति है। निश्चित रूप से, न तो जीसीसी 4.7.2 और न ही क्लैंग 3.2 मुझे 'constexpr a = foo (s0) संकलित करने की अनुमति देता है; ' – rici

23

constexpr एक मान इंगित करता है जो संकलन के दौरान निरंतर और ज्ञात है।
const एक मान इंगित करता है जो केवल स्थिर है; संकलन के दौरान जानना अनिवार्य नहीं है।

int sz; 
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation 
std::array<int, sz> data1;   // error! same problem 

constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant 
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr 

ध्यान दें कि स्थिरांक constexpr रूप में एक ही गारंटी प्रदान नहीं करता है, क्योंकि स्थिरांक वस्तुओं संकलन के दौरान जाना जाता मूल्यों के साथ प्रारंभ होने की जरूरत नहीं।

int sz; 
const auto arraySize = sz;  // fine, arraySize is const copy of sz 
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation 

सभी कॉन्स्टेक्स ऑब्जेक्ट्स हैं, लेकिन सभी कॉन्स्ट ऑब्जेक्ट्स कॉन्सएक्सप्रस नहीं हैं।

यदि आप कंपेलरों को यह गारंटी देना चाहते हैं कि एक चर के पास एक मान है जो संकलन-समय स्थिरांक की आवश्यकता वाले संदर्भों में उपयोग किया जा सकता है, तो उपकरण तक पहुंचने के लिए उपकरण कॉन्स्टेक्स नहीं है।

+1

मुझे आपकी व्याख्या बहुत पसंद आया..क्या आप कृपया इस बात पर अधिक टिप्पणी कर सकते हैं कि वास्तविक जीवन परिदृश्यों में संकलन समय स्थिरांक का उपयोग करने के लिए हमें किन मामलों की आवश्यकता हो सकती है। –

+1

@MayukhSarkar बस Google _C++ क्यों constexpr_, उदा। http://stackoverflow.com/questions/4748083/when-should-you-use-constexpr-capability-in-c11 –

4

constexpr प्रतीकात्मक निरंतर एक मान दिया जाना चाहिए जो संकलन समय पर जाना जाता है। उदाहरण के लिए:

constexpr int max = 100; 
void use(int n) 
{ 
    constexpr int c1 = max+7; // OK: c1 is 107 
    constexpr int c2 = n+7; // Error: we don’t know the value of c2 
    // ... 
} 

मामलों में जहां एक "चर" है कि एक मूल्य है कि संकलन समय पर नहीं जाना जाता है के साथ आरंभ नहीं हो जाता लेकिन आरंभीकरण के बाद बदल जाता है कभी नहीं के मूल्य सी ++ निरंतर का एक दूसरा रूप प्रदान करता है संभाल करने के लिए (एक कॉन्स)। उदाहरण के लिए:

constexpr int max = 100; 
void use(int n) 
{ 
    constexpr int c1 = max+7; // OK: c1 is 107 
    const int c2 = n+7; // OK, but don’t try to change the value of c2 
    // ... 
    c2 = 7; // error: c2 is a const 
} 

इस तरह के "स्थिरांक चर" दो कारणों के लिए बहुत आम हैं:

  1. सी ++ 98, constexpr नहीं था ताकि लोगों को स्थिरांक इस्तेमाल किया।
  2. सूची आइटम "वेरिएबल्स" जो निरंतर अभिव्यक्ति नहीं हैं (उनका मान संकलन समय पर ज्ञात नहीं है) लेकिन प्रारंभिकरण के बाद मानों को परिवर्तित नहीं करते हैं प्रारंभिक रूप से व्यापक रूप से उपयोगी होते हैं।
+10

शायद आपको यह उल्लेख करना चाहिए था कि आपके उत्तर में पाठ शब्दशः "प्रोग्रामिंग: सिद्धांतों और अभ्यास का उपयोग कर लिया गया है सी ++ "स्ट्रॉस्ट्रप द्वारा – Aky