आपको C ++ 11 में कॉन्स्टैक्स क्षमता का उपयोग कब करना चाहिए?


337

यह मुझे लगता है कि "फ़ंक्शन जो हमेशा 5 रिटर्न करता है" होने के कारण "फ़ंक्शन को कॉल करना" का अर्थ तोड़ना या पतला करना है। एक कारण होना चाहिए, या इस क्षमता की आवश्यकता है या यह C ++ 11 में नहीं होगा। ऐसा क्यों है?

// preprocessor.
#define MEANING_OF_LIFE 42

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

यह मुझे लगता है कि अगर मैंने एक फ़ंक्शन लिखा है जो शाब्दिक मान लौटाता है, और मैं एक कोड-समीक्षा के लिए आया था, तो कोई मुझे बताएगा, मुझे तब, वापसी 5 लिखने के बजाय एक निरंतर मूल्य घोषित करना चाहिए।


28
क्या आप एक पुनरावर्ती फ़ंक्शन को परिभाषित कर सकते हैं जो एक रिटर्न देता है constexpr? यदि हां, तो मैं एक उपयोग देख सकता हूं।
ेरेऑन

20
मेरा मानना ​​है कि प्रश्न "क्यों एक नए कीवर्ड (?) का परिचय दे सकता है यदि कंपाइलर खुद के लिए कटौती कर सकता है कि क्या किसी फ़ंक्शन का संकलन समय में मूल्यांकन किया जा सकता है या नहीं"। यह "एक कीवर्ड द्वारा गारंटीकृत" अच्छा लगता है, लेकिन मुझे लगता है कि जब भी संभव हो, बिना किसी कीवर्ड की आवश्यकता के, मैं इसकी गारंटी देना पसंद करूंगा।
कोस

6
@Kos: कोई व्यक्ति जो C ++ इंटर्नल के साथ अधिक बातचीत कर रहा है, वह शायद आपके प्रश्न को पसंद करेगा, लेकिन मेरा प्रश्न एक ऐसे व्यक्ति के दृष्टिकोण से आता है, जिसने C कोड पहले लिखा है, लेकिन C ++ 2011 के सभी कीवर्ड से परिचित नहीं है, और न ही C ++ कंप्लायंस कार्यान्वयन विवरण । संकलक अनुकूलन और निरंतर अभिव्यक्ति-कटौती के बारे में तर्क करने में सक्षम होने के कारण यह एक से अधिक उन्नत-उपयोगकर्ता प्रश्न के लिए एक विषय है।
वॉरेन पी

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

3
@Kos: आप के बारे में एक ही बात कह सकते हैं const। वास्तव में, अनिवार्य आशय है उपयोगी ! सरणी आयाम विहित उदाहरण हैं।
ऑर्बिट

जवाबों:


303

मान लीजिए कि यह कुछ अधिक जटिल है।

constexpr int MeaningOfLife ( int a, int b ) { return a * b; }

const int meaningOfLife = MeaningOfLife( 6, 7 );

अब आपके पास कुछ है जिसका मूल्यांकन अच्छी पठनीयता को बनाए रखते हुए एक निरंतरता तक किया जा सकता है और एक संख्या के लिए एक स्थिरांक स्थापित करने की तुलना में थोड़ा अधिक जटिल प्रसंस्करण की अनुमति देता है।

यह मूल रूप से स्थिरता को एक अच्छी सहायता प्रदान करता है क्योंकि यह अधिक स्पष्ट हो जाता है कि आप क्या कर रहे हैं। max( a, b )उदाहरण के लिए लें :

template< typename Type > constexpr Type max( Type a, Type b ) { return a < b ? b : a; }

इसकी एक बहुत ही सरल पसंद है, लेकिन इसका मतलब यह है कि यदि आप maxनिरंतर मूल्यों के साथ कॉल करते हैं, तो यह स्पष्ट रूप से संकलित समय पर गणना की जाती है, न कि रनटाइम पर।

एक और अच्छा उदाहरण एक DegreesToRadiansसमारोह होगा। हर कोई रेडियन की तुलना में डिग्री को आसानी से पढ़ पाता है। जबकि आप जान सकते हैं कि 180 डिग्री रेडियन में है यह बहुत स्पष्ट है इस प्रकार लिखा है:

const float oneeighty = DegreesToRadians( 180.0f );

यहाँ अच्छी जानकारी के बहुत सारे:

http://en.cppreference.com/w/cpp/language/constexpr


18
इसके साथ उत्कृष्ट बिंदु संकलक को यह बताने की कोशिश करना और संकलन समय पर मूल्य की गणना करना है। मैं उत्सुक हूं कि जब विशिष्ट अनुकूलन निर्दिष्ट किए जाते हैं तो कॉन्स्ट यह कार्यक्षमता क्यों नहीं प्रदान करता है? या करता है?
तमसुराजॉय

11
@ टैमस: अक्सर यह होगा लेकिन इसके लिए बाध्य नहीं है। constexpr संकलक को बाध्य करता है और यदि यह नहीं हो सकता है तो एक त्रुटि को थूक देगा।
गोज

20
मुझे अब दिख रहा है। पाप (0.5) एक और है। यह सी मैक्रोज़ को बड़े करीने से बदल देता है।
वॉरेन पी

10
मैं इसे एक नए साक्षात्कार के प्रश्न के रूप में देख सकता हूं: कॉन्स्ट्रेस और कॉन्स्ट्रेप कीवर्ड के बीच के अंतर को स्पष्ट करें।
वॉरेन पी

2
इस बिंदु को खुद के लिए दस्तावेजीकरण करने के एक तरीके के रूप में मैंने ऊपर और फिर से फ़ंक्शन के समान कोड को "कॉन्स्ट्रेप" के बजाय "कॉन्स्ट" लिखा। जैसा कि मैं Clang3.3 का उपयोग कर रहा हूं, -ऑप्टिकल-त्रुटियां और -std = c ++ 11 मुझे उम्मीद है कि बाद वाला संकलन नहीं करेगा। यह संकलित किया गया और "बाधा" मामले में भाग गया। क्या आपको लगता है कि यह एक क्लैंग एक्सटेंशन है या इस पोस्ट का जवाब दिए जाने के बाद से C ++ 11 के लिए एक ट्वीक है?
अब्बलेस्ट जूल

144

परिचय

constexprकार्यान्वयन को यह बताने के लिए एक तरीके के रूप में पेश नहीं किया गया था कि किसी चीज का मूल्यांकन एक संदर्भ में किया जा सकता है जिसके लिए एक स्थिर अभिव्यक्ति की आवश्यकता होती है ; अनुरूपण कार्यान्वयन C ++ 11 से पहले यह साबित करने में सक्षम है।

कुछ कार्यान्वयन जो साबित नहीं कर सकता है वह कोड के एक निश्चित टुकड़े का आशय है:

  • ऐसा क्या है जो डेवलपर इस इकाई के साथ व्यक्त करना चाहता है?
  • क्या हमें नेत्रहीन रूप से एक निरंतर अभिव्यक्ति में कोड का उपयोग करने की अनुमति देनी चाहिए , क्योंकि यह काम करता है?

बिना दुनिया के क्या होगा constexpr?

मान लें कि आप एक पुस्तकालय विकसित कर रहे हैं और महसूस करते हैं कि आप अंतराल में प्रत्येक पूर्णांक की राशि की गणना करने में सक्षम होना चाहते हैं (0,N]

int f (int n) {
  return n > 0 ? n + f (n-1) : n;
}

इरादे की कमी

एक संकलक आसानी से यह साबित कर सकता है कि अनुवाद के दौरान दिए गए तर्क को ज्ञात होने पर उपरोक्त फ़ंक्शन स्थिर-अभिव्यक्ति में कॉल करने योग्य है ; लेकिन आपने इसे एक इरादे के रूप में घोषित नहीं किया है - यह केवल मामला बन गया है।

अब कोई और साथ आता है, आपके फ़ंक्शन को पढ़ता है, संकलक के समान विश्लेषण करता है; " ओह, यह फ़ंक्शन एक स्थिर-अभिव्यक्ति में प्रयोग करने योग्य है!" , और निम्नलिखित कोड को लिखता है।

T arr[f(10)]; // freakin' magic

अनुकूलन

आप, एक "भयानक" पुस्तकालय डेवलपर के रूप में, तय करते हैं कि fजब आह्वान किया जाए तो परिणाम को कैश करना चाहिए; कौन अधिक से अधिक मूल्यों के एक ही सेट की गणना करना चाहेगा?

int func (int n) { 
  static std::map<int, int> _cached;

  if (_cached.find (n) == _cached.end ()) 
    _cached[n] = n > 0 ? n + func (n-1) : n;

  return _cached[n];
}

परिणाम

अपने मूर्खतापूर्ण अनुकूलन को शुरू करके, आपने अपने फ़ंक्शन के हर उपयोग को तोड़ दिया जो कि एक संदर्भ में होता है जहां एक निरंतर अभिव्यक्ति की आवश्यकता होती थी।

आपने कभी वादा नहीं किया कि यह कार्य एक स्थिर-अभिव्यक्ति में प्रयोग करने योग्य था , और इसके बिना constexprइस तरह का वादा करने का कोई तरीका नहीं होगा।


तो, हमें आवश्यकता क्यों है constexpr?

कॉन्स्टैक्स का प्राथमिक उपयोग इरादा घोषित करना है ।

यदि एक इकाई के रूप में चिह्नित नहीं है constexpr- यह एक निरंतर अभिव्यक्ति में इस्तेमाल करने का इरादा नहीं था ; और यहां तक ​​कि अगर यह है, तो हम ऐसे संदर्भ का निदान करने के लिए संकलक पर भरोसा करते हैं (क्योंकि यह हमारे इरादे की उपेक्षा करता है)।


25
यह संभवतः सही उत्तर है, क्योंकि C ++ 14 और C ++ 17 में हालिया परिवर्तन constexprअभिव्यक्ति में भाषा की एक व्यापक रेंज का उपयोग करने की अनुमति देते हैं । दूसरे शब्दों में, बहुत अधिक कुछ भी एनोटेट किया जा सकता है constexpr(शायद एक दिन यह सिर्फ इस वजह से दूर चला जाएगा?), और जब तक किसी को उपयोग करने constexprया न करने का मानदंड नहीं होता है, तो बहुत सारे कोड इस तरह लिखे जाएंगे ।
एलेकोव

4
@alecov निश्चित रूप से सब कुछ नहीं है ... I/O, syscallऔर dynamic memory allocationनिश्चित रूप से constexprइसके अलावा चिह्नित नहीं किया जा सकता है , सब कुछ नहीं होना चाहिए constexpr
जियाहो जू

1
@alecov कुछ कार्यों को रनटाइम पर निष्पादित किया जाना है और संकलन-समय पर ऐसा करना अर्थहीन है।
जियाहो जू

1
मुझे भी यह उत्तर सबसे अच्छा लगता है। संकलन समय मूल्यांकन एक साफ-सुथरा अनुकूलन है, लेकिन वास्तव में आपको जो मिलता है, constexprवह किसी प्रकार के व्यवहार की गारंटी है। जैसा constकरता है।
टॉम ज़ातो -

क्या संकलक मुझे इस संकलित-कम संस्करण की अनुमति देता है जो int f (int n) { return n > 0 ? n + f (n-1) : n;} T arr[f(10)]; मुझे कहीं भी संकलित करने के लिए नहीं मिल सकता है?
जेर

91

लीजिए std::numeric_limits<T>::max(): जो भी कारण हो, यह एक तरीका है। constexprयहां फायदेमंद होगा।

एक और उदाहरण: आप एक सी-ऐरे (या std::array) को घोषित करना चाहते हैं जो दूसरे ऐरे के जितना बड़ा हो। फिलहाल ऐसा करने का तरीका इस तरह है:

int x[10];
int y[sizeof x / sizeof x[0]];

लेकिन लिखने में सक्षम होना बेहतर नहीं होगा:

int y[size_of(x)];

इसके लिए धन्यवाद constexpr, आप कर सकते हैं:

template <typename T, size_t N>
constexpr size_t size_of(T (&)[N]) {
    return N;
}

1
अच्छा टेम्पलेट उपयोग के लिए +1, लेकिन यह कॉन्स्टैक्स के बिना बिल्कुल वैसा ही काम करेगा, न?
कोस

21
@Kos: नहीं। यह एक रनटाइम मान लौटाएगा। constexprफंक्शन को एक कंपाइल-टाइम वैल्यू (यदि यह हो सकता है) वापस करने के लिए बाध्य करता है।
deft_code

14
@Kos: इसके बिना constexprएरे साइज़ डिक्लेरेशन में इस्तेमाल नहीं किया जा सकता है, न ही टेम्प्लेट तर्क के रूप में, भले ही फ़ंक्शन कॉल का परिणाम एक संकलन-समय स्थिर हो या न हो। ये दोनों मूल रूप से केवल उपयोग के मामले हैं, constexprलेकिन कम से कम टेम्पलेट तर्क उपयोग-केस महत्वपूर्ण है।
कोनराड रुडोल्फ

2
"जो भी कारण हो, यह एक विधि है": कारण यह है कि C ++ 03 में केवल संकलन समय पूर्णांक हैं, लेकिन कोई अन्य संकलन समय प्रकार नहीं है, इसलिए केवल C ++ 11 से पहले के लिए कोई विधि मनमाने प्रकार के लिए काम कर सकती है।
सेबेस्टियन मच

5
@LwCui नहीं, यह "ठीक" नहीं है: जीसीसी डिफ़ॉल्ट रूप से कुछ चीजों के बारे में है। -pedanticविकल्प का उपयोग करें और इसे एक त्रुटि के रूप में चिह्नित किया जाएगा।
कोनराड रूडोल्फ

19

constexprफ़ंक्शंस वास्तव में अच्छे हैं और सी ++ के लिए एक बढ़िया अतिरिक्त है। हालाँकि, आप सही हैं कि अधिकांश समस्याओं का हल मैक्रोज़ के साथ असमान रूप से काम कर सकता है।

हालाँकि, उपयोग में से एक constexprमें कोई C ++ 03 समतुल्य, टाइप किए गए स्थिरांक नहीं हैं।

// This is bad for obvious reasons.
#define ONE 1;

// This works most of the time but isn't fully typed.
enum { TWO = 2 };

// This doesn't compile
enum { pi = 3.1415f };

// This is a file local lvalue masquerading as a global
// rvalue.  It works most of the time.  But May subtly break
// with static initialization order issues, eg pi = 0 for some files.
static const float pi = 3.1415f;

// This is a true constant rvalue
constexpr float pi = 3.1415f;

// Haven't you always wanted to do this?
// constexpr std::string awesome = "oh yeah!!!";
// UPDATE: sadly std::string lacks a constexpr ctor

struct A
{
   static const int four = 4;
   static const int five = 5;
   constexpr int six = 6;
};

int main()
{
   &A::four; // linker error
   &A::six; // compiler error

   // EXTREMELY subtle linker error
   int i = rand()? A::four: A::five;
   // It not safe use static const class variables with the ternary operator!
}

//Adding this to any cpp file would fix the linker error.
//int A::four;
//int A::six;

12
क्या आप स्पष्ट कर सकते हैं कि "अत्यधिक सूक्ष्म लिंकर त्रुटि"? या कम से कम एक स्पष्टीकरण के लिए एक संकेतक प्रदान करें?
enobayram

4
@enobayram, टर्नरी ऑपरेटर ऑपरेंड का पता लेता है। यह कोड से स्पष्ट नहीं है। सब कुछ ठीक संकलित करता है, लेकिन लिंक विफल हो जाता है क्योंकि पते का fourसमाधान नहीं होता है। मुझे वास्तव में यह पता लगाने के लिए खुदाई करनी थी कि मेरे static constचर का पता कौन ले रहा है ।
deft_code

23
"यह स्पष्ट कारणों से बुरा है": सबसे स्पष्ट कारण अर्धविराम है, है ना?
टोनीके

4
"अत्यधिक सूक्ष्म लिंकर त्रुटि" ने मुझे पूरी तरह से हैरान कर दिया है। न तो fourहै और न ही fiveदायरे में हैं।
स्टीवन लू

3
नए enum classप्रकार को भी देखें , यह एनम के कुछ मुद्दों को ठीक करता है।
निनमोंकी

14

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

मेरे सिर के ऊपर से एक और उदाहरण यह होगा कि वर्ग इंटरफेस के लिए, आप चाहें तो व्युत्पन्न प्रकार कुछ ऑपरेशन के लिए अपने स्वयं के स्थिरांक को परिभाषित कर सकते हैं।

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

एसओ पर चारों ओर से झाँकने के बाद, ऐसा लगता है कि अन्य लोग कुछ उदाहरणों के साथ आए हैं जो कि कॉन्स्ट्रेक्स के साथ संभव हो सकते हैं।


"एक इंटरफ़ेस का हिस्सा बनने के लिए जो आपको फ़ंक्शन के लिए मिला है"?
डैनियल ईयरविकर

अब जब मैं इसकी उपयोगिता देख सकता हूं, तो मैं C ++ 0x के बारे में थोड़ा और उत्साहित हूं। यह एक सोची समझी बात लगती है। मुझे पता था कि वे अवश्य होंगे। वे भाषा मानक uber-geeks शायद ही कभी यादृच्छिक बातें करते हैं।
वॉरेन पी

मैं लैम्बदास के बारे में अधिक उत्साहित हूं, थ्रेडिंग मॉडल, इनिशलाइज़र_लिस्ट, रेवल्यू रेफरेंस, वैरेडिक टेम्प्लेट, नए बाइंड ओवरलोड्स ... आगे देखने के लिए काफी कुछ है।
लूका

1
अरे हाँ, लेकिन मैं पहले से ही कई अन्य भाषाओँ में लैम्ब्डा / क्लोज़र को समझता हूँ। constexprएक शक्तिशाली संकलन-समय अभिव्यक्ति मूल्यांकन प्रणाली के साथ संकलक में अधिक विशेष रूप से उपयोगी है। C ++ के पास वास्तव में उस डोमेन में कोई सहकर्मी नहीं है। (यह C ++ 11, IMHO के लिए एक मजबूत प्रशंसा है)
वॉरेन पी

11

स्ट्रॉन्स्ट्रप के भाषण से "गोइंग नेटिव 2012" पर:

template<int M, int K, int S> struct Unit { // a unit in the MKS system
       enum { m=M, kg=K, s=S };
};

template<typename Unit> // a magnitude with a unit 
struct Value {
       double val;   // the magnitude 
       explicit Value(double d) : val(d) {} // construct a Value from a double 
};

using Speed = Value<Unit<1,0,-1>>;  // meters/second type
using Acceleration = Value<Unit<1,0,-2>>;  // meters/second/second type
using Second = Unit<0,0,1>;  // unit: sec
using Second2 = Unit<0,0,2>; // unit: second*second 

constexpr Value<Second> operator"" s(long double d)
   // a f-p literal suffixed by ‘s’
{
  return Value<Second> (d);  
}   

constexpr Value<Second2> operator"" s2(long double d)
  // a f-p literal  suffixed by ‘s2’ 
{
  return Value<Second2> (d); 
}

Speed sp1 = 100m/9.8s; // very fast for a human 
Speed sp2 = 100m/9.8s2; // error (m/s2 is acceleration)  
Speed sp3 = 100/9.8s; // error (speed is m/s and 100 has no unit) 
Acceleration acc = sp1/0.5s; // too fast for a human

2
यह उदाहरण स्ट्रॉस्ट्रुप के पेपर सॉफ्टवेयर डेवलपमेंट फॉर इन्फ्रास्ट्रक्चर में भी पाया जा सकता है ।
Matthieu Poullet

क्लैंग -३.३: त्रुटि: कॉन्स्ट्रेक्स फंक्शन का रिटर्न टाइप 'वैल्यू <सेकंड>' कोई शाब्दिक प्रकार नहीं है
मित्जा

यह अच्छा है, लेकिन जो इस तरह कोड में शाब्दिक डालता है। यदि आप एक इंटरैक्टिव कैलकुलेटर लिख रहे थे, तो आपके लिए आपके कंपाइलर "अपनी इकाइयों की जाँच करें" से समझ में आएगा।
बॉबोबो

5
@ बोबोबोबो या यदि आप मार्स क्लाइमेट ऑर्बिटर के लिए नेविगेशन सॉफ्टवेयर लिख रहे थे, शायद :)
जेरेमी फ्रेज़र

1
इसे संकलित करने के लिए - 1. शाब्दिक प्रत्ययों में अंडरस्कोर का उपयोग करें। 2. 100_m के लिए ऑपरेटर जोड़ें "" _m। 3. 100.0_m का उपयोग करें, या एक अधिभार जोड़ें जो लंबे समय तक अहस्ताक्षरित स्वीकार करता है। 4. मूल्य निर्माणकर्ता अवरोध की घोषणा करें। 5. इसी तरह के ऑपरेटर / मूल्य वर्ग में जोड़ें: कॉन्स्ट्रेक्टर ऑटो ऑपरेटर / (कास्ट वैल्यू <Y> और अन्य) कास्ट {रिटर्न वैल्यू <यूनिट <TheUnit :: m - वैल्यू <Y> :: TheUnit :: m, TheUnit :: kg - मान <y> :: TheUnit :: kg, TheUnit :: s - मूल्य <Y> :: TheUnit :: s >> (val / other.val); }। जहाँ TheUnit, यूनिट के लिए टाइप क्लास में टाइप क्लास के लिए जोड़ा जाता है।
0kcats

8

एक अन्य उपयोग (अभी तक उल्लेख नहीं किया गया है) constexprनिर्माता हैं। यह संकलित समय स्थिरांक बनाने की अनुमति देता है जिसे रनटाइम के दौरान आरंभीकृत नहीं करना पड़ता है।

const std::complex<double> meaning_of_imagination(0, 42); 

जोड़ी कि उपयोगकर्ता परिभाषित शाब्दिक के साथ और आपको शाब्दिक उपयोगकर्ता परिभाषित वर्गों के लिए पूर्ण समर्थन है।

3.14D + 42_i;

6

मेटाप्रोग्रामिंग के साथ एक पैटर्न हुआ करता था:

template<unsigned T>
struct Fact {
    enum Enum {
        VALUE = Fact<T-1>*T;
    };
};

template<>
struct Fact<1u> {
    enum Enum {
        VALUE = 1;
    };
};

// Fact<10>::VALUE is known be a compile-time constant

मेरा मानना ​​है कि constexprविशेषज्ञता, SFINAE और सामान के साथ टेम्प्लेट और अजीब निर्माणों की आवश्यकता के बिना आपको ऐसे निर्माणों को लिखने के लिए पेश किया गया था - लेकिन ठीक उसी तरह जैसे आप एक रन-टाइम फ़ंक्शन लिखते हैं, लेकिन इस गारंटी के साथ कि परिणाम संकलन में निर्धारित किया जाएगा। -समय।

हालाँकि, ध्यान दें कि:

int fact(unsigned n) {
    if (n==1) return 1;
    return fact(n-1)*n;
}

int main() {
    return fact(10);
}

इसके साथ संकलित करें g++ -O3और आप देखेंगे कि fact(10)वास्तव में संकलन-समय पर विकसित किया गया है!

एक वीएलए-जागरूक संकलक (इसलिए C99 मोड में C संकलक या C99 एक्सटेंशन के साथ C ++ संकलक) भी आपको करने की अनुमति दे सकता है:

int main() {
    int tab[fact(10)];
    int tab2[std::max(20,30)];
}

लेकिन यह इस समय गैर-मानक सी ++ है - constexprयह मुकाबला करने का एक तरीका जैसा दिखता है (उपरोक्त मामले में वीएलए के बिना भी)। और टेम्पलेट तर्क के रूप में "औपचारिक" निरंतर अभिव्यक्ति की आवश्यकता की समस्या अभी भी है।


तथ्य समारोह का मूल्यांकन संकलन-समय पर नहीं किया जाता है। इसके लिए बाधा होना चाहिए और केवल एक विवरणी होना चाहिए।
सुमंत

1
@ सुमंत: आप सही हैं कि इसका संकलन-समय पर मूल्यांकन नहीं होना चाहिए, लेकिन यह है! मैं इस बात का जिक्र कर रहा था कि वास्तव में कंपाइलर्स में क्या होता है। हाल के GCC पर इसे संकलित करें, परिणामी asm देखें और अगर आपको मुझ पर विश्वास नहीं है तो अपने लिए जाँच करें!
कोस

जोड़ने की कोशिश करें std::array<int, fact(2)>और आप उस तथ्य () का संकलन-समय पर मूल्यांकन नहीं करेंगे। यह सिर्फ जीसीसी ऑप्टिमाइज़र है जो एक अच्छा काम कर रहा है।

1
यही मैंने कहा है ... क्या मैं वास्तव में अस्पष्ट हूं? अंतिम पैराग्राफ देखें
कोस

5

बस एक परियोजना को c ++ 11 पर स्विच करना शुरू कर दिया है और constexpr के लिए एक पूरी तरह से अच्छी स्थिति में आया है जो एक ही ऑपरेशन करने के वैकल्पिक तरीकों को साफ करता है। यहां मुख्य बिंदु यह है कि आप फ़ंक्शन को सरणी आकार घोषणा में केवल तभी रख सकते हैं जब इसे कॉन्स्टैक्स घोषित किया जाए। ऐसी कई स्थितियाँ हैं, जहाँ मैं इसे कोड के क्षेत्र के साथ आगे बढ़ते हुए बहुत उपयोगी होते हुए देख सकता हूँ।

constexpr size_t GetMaxIPV4StringLength()
{
    return ( sizeof( "255.255.255.255" ) );
}

void SomeIPFunction()
{
    char szIPAddress[ GetMaxIPV4StringLength() ];
    SomeIPGetFunction( szIPAddress );
}

4
यह समान रूप से लिखा जा सकता है: const size_t MaxIPV4StringLength = sizeof ("255.255.255.255");
जॉन

static inline constexpr const autoशायद बेहतर है।
जियाहो जू Jia

3

अन्य सभी उत्तर महान हैं, मैं सिर्फ एक बात का एक अच्छा उदाहरण देना चाहता हूं जो आप कर सकते हैं, जो कि अद्भुत है। See-Phit ( https://github.com/rep-movsd/see-phit/blob/master/seephit.h ) एक संकलन समय HTML पार्सर और टेम्पलेट इंजन है। इसका मतलब है कि आप HTML को अंदर रख सकते हैं और एक ऐसा पेड़ निकाल सकते हैं जो हेरफेर करने में सक्षम है। संकलित समय पर किए गए पार्सिंग होने से आप थोड़ा अतिरिक्त प्रदर्शन कर सकते हैं।

जीथब पृष्ठ उदाहरण से:

#include <iostream>
#include "seephit.h"
using namespace std;



int main()
{
  constexpr auto parser =
    R"*(
    <span >
    <p  color="red" height='10' >{{name}} is a {{profession}} in {{city}}</p  >
    </span>
    )*"_html;

  spt::tree spt_tree(parser);

  spt::template_dict dct;
  dct["name"] = "Mary";
  dct["profession"] = "doctor";
  dct["city"] = "London";

  spt_tree.root.render(cerr, dct);
  cerr << endl;

  dct["city"] = "New York";
  dct["name"] = "John";
  dct["profession"] = "janitor";

  spt_tree.root.render(cerr, dct);
  cerr << endl;
}

1

आपका मूल उदाहरण वह उसी तर्क के रूप में कार्य करता है जैसे स्वयं को स्थिर करता है। क्यों का उपयोग करें

static const int x = 5;
int arr[x];

ऊपर

int arr[5];

क्योंकि यह अधिक रखरखाव योग्य है। कॉन्स्टेक्स का उपयोग करना, मौजूदा मेटाप्रोग्रामिंग तकनीकों की तुलना में लिखने और पढ़ने के लिए बहुत तेज़ है।


0

यह कुछ नए अनुकूलन कर सकता है। constपारंपरिक रूप से प्रकार प्रणाली के लिए एक संकेत है, और इसका उपयोग अनुकूलन के लिए नहीं किया जा सकता है (उदाहरण के लिए constसदस्य फ़ंक्शन const_castवैसे भी, कानूनी रूप से वस्तु को संशोधित और संशोधित constकर सकता है , इसलिए अनुकूलन के लिए भरोसा नहीं किया जा सकता है)।

constexprइसका मतलब है कि अभिव्यक्ति वास्तव में स्थिर है, बशर्ते फ़ंक्शन के लिए इनपुट कास्ट हैं। विचार करें:

class MyInterface {
public:
    int GetNumber() const = 0;
};

यदि इसे किसी अन्य मॉड्यूल में उजागर किया जाता है, तो कंपाइलर भरोसा नहीं कर सकता है कि GetNumber()हर बार अलग-अलग मानों को वापस नहीं लौटाया जाएगा - यहां तक ​​कि बीच में कोई गैर-कॉस्ट कॉल के साथ लगातार - क्योंकि constकार्यान्वयन में दूर डाला जा सकता था। (जाहिर है कि किसी भी प्रोग्रामर ने ऐसा किया है जिसे गोली मार दी जानी चाहिए, लेकिन भाषा इसकी अनुमति देती है, इसलिए संकलक को नियमों का पालन करना चाहिए।)

जोड़ना constexpr:

class MyInterface {
public:
    constexpr int GetNumber() const = 0;
};

कंपाइलर अब एक ऑप्टिमाइज़ेशन लागू कर सकता है, जहाँ रिटर्न वैल्यू GetNumber()कैश्ड है और अतिरिक्त कॉल को समाप्त कर देता है GetNumber(), क्योंकि constexprएक मजबूत गारंटी है कि रिटर्न का मूल्य बदल जाएगा।


वास्तव में अनुकूलन में इस्तेमाल किया const जा सकता है ... यह एक IIRC के बाद भी एक मूल्य परिभाषित कास्ट को संशोधित करने के लिए अपरिभाषित व्यवहार है const_cast। मुझे उम्मीद है कि यह constसदस्य कार्यों के अनुरूप होगा , लेकिन मुझे मानक के साथ जांच करने की आवश्यकता होगी। इसका मतलब यह होगा कि कंपाइलर सुरक्षित रूप से वहां अनुकूलन कर सकता है।
कोस

1
@Warren: अगर वास्तव में अनुकूलन किया जाता है तो इससे कोई फर्क नहीं पड़ता, यह सिर्फ अनुमति है। @Kos: यह एक छोटी-सी सूक्ष्मता है कि यदि मूल वस्तु को कॉन्स्टेंट ( बनाम ) घोषित नहीं किया गया था , तो यह पॉइंटर को दूर करके पॉइंटर / रेफरेंस पर इसे संशोधित करना सुरक्षित है। अन्यथा, हमेशा अपरिभाषित व्यवहार को लागू करेगा, और बेकार हो जाएगा :) इस मामले में, संकलक को मूल वस्तु के कास्ट-नेस के बारे में कोई जानकारी नहीं है, इसलिए यह नहीं बता सकता है। int xconst int xconst_castconst_cast
AshleysBrain 1

@ मुझे नहीं लगता कि const_cast यहां एकमात्र मुद्दा है। कॉन्स्ट विधि को एक वैश्विक चर को पढ़ने और यहां तक ​​कि संशोधित करने की अनुमति है। इसके विपरीत, apther थ्रेड से कोई भी कॉल के बीच कास्ट ऑब्जेक्ट को संशोधित कर सकता है।
enobayram

1
"= 0" यहां मान्य नहीं है और इसे हटा दिया जाना चाहिए। मैं इसे स्वयं करूँगा, लेकिन मुझे यकीन नहीं है कि यह एसओ प्रोटोकॉल के अनुरूप है।
KnowItAllWannabe

दोनों उदाहरण अमान्य हैं: पहले वाले ( int GetNumber() const = 0;) को GetNumber()विधि को आभासी घोषित करना चाहिए । दूसरा ( constexpr int GetNumber() const = 0;क्योंकि शुद्ध विनिर्देशक () मान्य नहीं है = 0) विधि का तात्पर्य आभासी होने के लिए, लेकिन constexpr के जरूरी आभासी नहीं हो (संदर्भ: en.cppreference.com/w/cpp/language/constexpr )
STJ

-1

कब उपयोग करें constexpr:

  1. जब भी कोई संकलन समय स्थिर होता है।

जब मैं आपसे सहमत हूं, तो यह उत्तर स्पष्ट नहीं करता है कि constexpr प्रीप्रोसेसर मैक्रोज़ या क्यों पसंद किया जाना चाहिए const
स्नेफेल

-3

यह कुछ के लिए उपयोगी है

// constants:
const int MeaningOfLife = 42;

// constexpr-function:
constexpr int MeaningOfLife () { return 42; }

int some_arr[MeaningOfLife()];

इसे ट्रेस क्लास या लाइक के साथ टाई करें और यह काफी उपयोगी हो जाता है।


4
आपके उदाहरण में यह एक सादे स्थिर पर शून्य लाभ प्रदान करता है, इसलिए यह वास्तव में सवाल का जवाब नहीं देता है।
jalf

यह एक विरोधाभासी उदाहरण है, कल्पना करें कि अर्थऑफलाइफ () कहीं और से अपना मूल्य प्राप्त करता है, तो एक अन्य फ़ंक्शन या एक #define या श्रृंखला उपचार कहें। आप नहीं जानते कि यह क्या रिटर्न देता है, यह लाइब्रेरी कोड हो सकता है। अन्य उदाहरण, एक अपरिवर्तनीय कंटेनर की कल्पना करते हैं जिसमें एक कॉन्स्ट्रेक्स आकार () विधि है। अब आप int arrest [कंटेन.size ()] कर सकते हैं;
प्लाविसी

2
@plivesey क्या आप एक बेहतर उदाहरण के साथ अपना जवाब संपादित कर सकते हैं।
मुकेश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.