2012-10-23 7 views
15

आम तौर पर, constexpr दुष्प्रभावों से मुक्त होना चाहिए। हालांकि, मैंने अभी पाया है कि फेंकने वाले अपवादों के रचनाकारों में दुष्प्रभावों का उपयोग करना संभव है। उस तकनीक का उपयोग constexpr कार्यों के लिए assert() को अनुकरण करने के लिए किया जा सकता है, क्योंकि यह निम्न प्रोग्राम में प्रदर्शित होता है।क्या यह constexpr द्वारा फेंक दिया अपवादों में साइड इफेक्ट्स का उपयोग करने के लिए कानूनी है?

#include <iostream> 
#include <cstdlib> 
#include <stdexcept> 

struct constexpr_precond_violated : std::logic_error 
{ 
    constexpr_precond_violated(const char* msg) : 
    std::logic_error(msg) 
    { 
    std::cerr << msg << '\n'; 
    abort(); // to get a core dump 
    } 
}; 

#define TO_STRING_IMPL(x) #x 
#define TO_STRING(x) TO_STRING_IMPL(x) 

#define CONSTEXPR_PRECOND(cond, value) \ 
    ((!(cond)) ? throw constexpr_precond_violated(\ 
    "assertion: <" #cond "> failed (file: " \ 
    __FILE__ ", line: " TO_STRING(__LINE__) ")") \ 
    : (value)) 

constexpr int divide(int x, int y) 
{ 
    return CONSTEXPR_PRECOND(y != 0, x/y); 
} 

int main(int argc, char** argv) 
{ 
    // The compiler cannot know argc, so it must be evaluated at runtime. 
    // If argc is 2, the precondition is violated. 
    return divide(100, argc - 2); 
} 

मैंने इसे जी ++ 4.7.2 और क्लैंग ++ 3.1 के साथ परीक्षण किया। जब पूर्व शर्त विफल हो जाती है, तो आपको त्रुटि स्थान और कोर डंप मिलता है।

./constexpr_assert some_arg 
assertion: <y != 0> failed (file: constexpr_assert.cpp, line: 26) 
Aborted (core dumped) 

तो यह वर्तमान कंपाइलर्स के साथ काम करता है, लेकिन क्या यह कानूनी सी ++ 11 है?

+1

ब्याज से, क्या होता है यदि आप संकलन-समय निरंतर '0' को दूसरे विभाजन के रूप में 'divide()' के रूप में आपूर्ति करते हैं? क्या * कंपाइलर * "अपवाद फेंकता है"? :) –

+0

static_assert (विभाजन (1, 0)> = 0, "परीक्षण"); बस वापसी विभाजन (1, 0) संकलित नहीं करेगा; क्लैंग के साथ संकलित करता है और केवल रनटाइम पर विफल रहता है। –

+3

आपको लगातार अभिव्यक्तियों और 'constexpr' फ़ंक्शन के बीच अंतर करने के लिए सावधान रहना चाहिए। "Constexpr' जैसे कुछ दुष्प्रभावों से मुक्त होना चाहिए" अपरिहार्य है। 'Constexpr' के बारे में सोचें क्योंकि एक कीवर्ड से अधिक नहीं है ('स्थिर' दिमाग में आता है)। –

उत्तर

14

यह कानूनी है।

प्रत्येक constexpr समारोह के लिए वहाँ कुछ तर्क मान जो एक निरंतर अभिव्यक्ति (§7.1.5/5) में परिणाम होना चाहिए:

एक constexpr समारोह के लिए, यदि कोई समारोह तर्क मान है कि मौजूद ऐसे फ़ंक्शन इनवोकेशन प्रतिस्थापन निरंतर अभिव्यक्ति (5.1 9) उत्पन्न करेगा, कार्यक्रम खराब बना हुआ है; कोई निदान की आवश्यकता नहीं है।

ध्यान दें कि यह मतलब नहीं है कि हर संभव तर्क मूल्य स्थिर अभिव्यक्ति में परिणाम चाहिए। divide में स्पष्ट रूप से कुछ तर्क मान हैं जो निरंतर अभिव्यक्ति में परिणाम देते हैं: divide(1, 1) एक साधारण उदाहरण है। तो, परिभाषा स्पष्ट रूप से मान्य है।

लेकिन divide(1, 0) कहा जा सकता है? हाँ यह कर सकते हैं। एक बराबर गैर constexpr को

एक constexpr कार्य करने के लिए एक कॉल एक फोन के रूप में एक ही परिणाम पैदा करता है: वहाँ एक constexpr समारोह या एक "सामान्य" समारोह (§7.1.5/7) लागू के बीच लगभग कोई अंतर नहीं है सभी मामलों में कार्य करें कि constexpr फ़ंक्शन पर कॉल निरंतर अभिव्यक्ति में दिखाई दे सकता है।

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

पूर्णता के लिए, चलो देखते हैं कि क्या एक निरंतर अभिव्यक्ति (§5.19/2) बनाता है:

एक सशर्त अभिव्यक्ति एक कोर निरंतर अभिव्यक्ति है जब तक कि यह एक के रूप में निम्न में से एक शामिल है संभावित रूप से मूल्यांकन किया गया उप-संपीड़न (§3.2), लेकिन तार्किक और (§5.14), तार्किक OR (§5.15), और सशर्त (§5.16) संचालन का मूल्यांकन नहीं किया गया है, जिनका मूल्यांकन नहीं किया गया है माना जाता है [...]।

तो, divide(1, 1) एक निरंतर अभिव्यक्ति है, लेकिन divide(1, 0) नहीं है।यदि आपने टेम्पलेट पैरामीटर में divide(1, 0) का उपयोग किया है, तो प्रोग्राम खराब हो जाएगा। लेकिन अन्यथा यह ठीक है।

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