2016-03-10 6 views
8

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

#include <iostream> 
#include <array> 

template<typename T> class MyClass 
{ 
public: 
    static constexpr std::array<T,4> ARRAY {{4, 3, 1, 5}}; 
}; 

int main() 
{ 
    constexpr std::array<int, 4> my_array(MyClass<int>::ARRAY); // works fine -> can use the ARRAY to initialize constexpr std::array 

    constexpr int VALUE = 5*MyClass<int>::ARRAY[0]; // works also fine 

    int value; 
    value = my_array[0]; // can assign from constexpr 
    value = MyClass<int>::ARRAY[0]; // undefined reference to `MyClass<int>::ARRAY 

    std::cout << VALUE << std::endl; 
    std::cout << value << std::endl; 

    return 0; 
} 

जहां तक ​​मेरा constexpr समझने के संकलन समय स्थिरांक के लिए है। तो संकलक पहले से ही कुछ गणना कर सकता है, उदाहरण के लिए VALUE की गणना करने के लिए। इसके अलावा मैं स्पष्ट रूप से constexpr std::array<,> परिभाषित कर सकता हूं, जिससे मैं रनटाइम चर के मानों को असाइन कर सकता हूं। मैं उम्मीद करता हूं कि लोडर ऑपरेशन से बचने के लिए कंपाइलर को पहले से ही value = 4 निष्पादन योग्य प्रोग्राम में सेट करना होगा। हालांकि, मैं स्थिर सदस्य से सीधे असाइन नहीं कर सकते,, त्रुटि

undefined reference to `MyClass<int>::ARRAY' 
clang-3.7: error: linker command failed with exit code 1 

जो मेरे लिए कोई मतलब नहीं है हो रही है क्योंकि इसे किसी अन्य constexpr चर का एक मध्यवर्ती कदम के साथ किया जा सकता है।

तो मेरा सवाल यह है कि: किसी क्लास का एक स्थिर कॉन्स्टेक्स सदस्य किसी रनटाइम चर को असाइन क्यों नहीं किया जा सकता है?

नोट: मेरे MWE में कक्षा एक टेम्पलेट वर्ग है, जो त्रुटि को प्रभावित नहीं करती है। हालांकि, मैं मूल रूप से इस विशेष मामले में रूचि रखता था, जिसे मैं एक गैर-टेम्पलेट वर्ग के रूप में अधिक सामान्य होने की उम्मीद करता हूं।

(संकलक clang++ या g++-std=c++11 साथ है - वे एक ही त्रुटि दिखा सकते हैं)

संपादित करें: @Bryan चेन: उत्पादन लाइनों भूल। अब जोड़ा गया है

+0

'clang ++ 'में यह समस्या है: http://coliru.stacked-crooked.com/a/e9698f2bb249e509। लेकिन 'जी ++' काम करता है: http://coliru.stacked-crooked.com/a/5ef23fe29b0aaa28। क्लैंग बग? –

+0

वीएस2015 यह कहता है: 'टाइप के लिए कक्षा में प्रारंभिक' कॉन्स्ट std :: array 'अभी तक कार्यान्वित नहीं किया गया है; स्थिर सदस्य रनटाइम पर अनियंत्रित रहेगा लेकिन स्थिर-अभिव्यक्तियों में उपयोग समर्थित है। आप कुछ इसी तरह से चल रहे हो सकता है। –

+0

@ ब्रायन: मैं निर्दोष था। मेरे पास g ++ 4.8.5 इंस्टॉल है, जो अभी तक C++ 14 का समर्थन नहीं करता है। लेकिन मुझे उम्मीद है कि यह पहले से ही सी ++ 11 के लिए काम करेगा !? – marlam

उत्तर

7

undefined reference एक लिंकर त्रुटि है। नियम यह है कि यदि एक चर odr-used है तो इसकी परिभाषा होनी चाहिए। यह constexpr चर के लिए भी लागू होता है।

अधिकांश ओडीआर नियमों की तरह, इसका उल्लंघन करना बिना किसी निदान के अनिश्चित व्यवहार है (जो समझा सकता है कि आपने मूल्य के अपने कुछ उपयोगों के लिए कोई निदान क्यों नहीं देखा)।

त्रुटि को ठीक करने के लिए, कक्षा के बाहर एक परिभाषा जोड़ें:

template<typename T> constexpr std::array<T,4> MyClass<T>::ARRAY; 

चूंकि यह आप वास्तव में शीर्ष लेख में इस डाल सकते हैं, के रूप में हमेशा की तरह मामले का विरोध किया जहां परिभाषा ठीक एक में चला जाता है एक टेम्पलेट है .cpp फ़ाइल।


मुख्य यहां मुद्दा यह है कि क्या ओडीआर उपयोग रूप ARRAY[0] गिना जाता है।this detailed post के अनुसार, सी ++ 11 और सी ++ 14 में, एक सरणी को अनुक्रमणित करना odr-use के रूप में गिना जाता है, लेकिन यह DR 1926 द्वारा C++ 14 के खिलाफ दायर किया गया था, odr-use नहीं था।

हालांकि, जो बिल्टिन सरणी के बारे में बात कर रहा है। आईडीके चाहे एक ही तर्क std::array पर लागू होता है, मुझे समझने के लिए [basic.def.odr]/3 का पाठ मिलता है। informal definition on cppreference के अनुसार, std::array::operator[] सरणी के odr-use का कारण बनता है क्योंकि इसका वापसी मान सरणी के संदर्भ को बांधता है।

+0

Thx पर परिवर्तनीय हो सकते हैं। क्या मैं सही समझता हूं, कि अन्य constexpr वस्तुओं के लिए संकलन समय पर उपयोग _not_ odr-use है और इसलिए कोई परिभाषा की आवश्यकता नहीं है? दूसरे शब्दों में: कंपाइलर 'ऑपरेटर []' का उपयोग करके 'VALUE' की गणना कर सकता है क्योंकि इसे संदर्भ (और इसलिए कोई परिभाषा नहीं) के संदर्भ की आवश्यकता नहीं है, लेकिन रनटाइम 'मान' पर गणना नहीं की जा सकती क्योंकि एक एड्रेस की आवश्यकता होती है और इसलिए एक परिभाषा है? – marlam

+0

@marlam मुझे लगता है कि वे दोनों odr-use हैं, लेकिन यह संकलक का केवल कुछ विवरण है जिसे मैं नहीं जानता जिसके बारे में यह एक मामले में त्रुटि देता है लेकिन दूसरे नहीं। –

4

इस कारण से मैं हमेशा एक constexpr समारोह से constexpr वस्तुओं को वापस।

नीचे संशोधित कोड। ध्यान दें कि std::array<> में सी ++ 14 की कमी के कारण आपको operator[] को काम करने की अनुमति देने के लिए const std::array वापस करना होगा।

#include <iostream> 

#include <iostream> 
#include <array> 

template<typename T> class MyClass 
{ 
public: 
    static constexpr const std::array<T,4> ARRAY() { return {4, 3, 1, 5}; }; 
}; 

int main() 
{ 
    constexpr std::array<int, 4> my_array(MyClass<int>::ARRAY()); // works fine -> can use the ARRAY to initialize constexpr std::array 

    constexpr int VALUE = 5 * MyClass<int>::ARRAY()[0]; // works also fine 

    int value; 
    value = my_array[0]; // can assign from constexpr 
    value = MyClass<int>::ARRAY()[0]; // undefined reference to `MyClass<int>::ARRAY 

    std::cout << VALUE << std::endl; 
    std::cout << value << std::endl; 

    return 0; 
} 

अपेक्षित परिणाम:

20 
4 
+0

Thx! क्या मैं इसे सही समझता हूं, कि सबस्क्रिप्ट ऑपरेटर संकलन समय गणना के लिए काम करेगा लेकिन रनटाइम पर नहीं? और क्या यह 'std :: array' की एक विशेष कमी है या क्या यह स्थिति अधिक बार दिखाई देती है (जैसा कि आप कहते हैं, आप constexpr फ़ंक्शन से constexpr ऑब्जेक्ट भी वापस करते हैं)। और क्या यह तय होने की संभावना है या ऐसा होने का कारण है? और अंत में: एक समारोह के माध्यम से सरणी प्राप्त करने के लिए एक डिजाइन दोष नहीं है? – marlam

+0

@marlam इसे C++ 17 में ठीक किया जा रहा है। ऐसा इसलिए है क्योंकि std :: array का ऑपरेटर [] mutable case में constexpr नहीं है (इंटरफ़ेस को C++ 11 में परिभाषित किया गया था और वे C++ 14 में इसे अपडेट करना भूल गए थे जब constexpr ऑब्जेक्ट्स mutable करने में सक्षम थे)। तो सबस्क्रिप्ट ऑपरेटर वर्तमान में गैर-कॉन्स्टेक्सर सरणी के लिए किसी भी मामले में काम करेगा और एक कॉन्स कॉन्स्टेक्स सरणी के लिए काम करेगा। यह कमी आम नहीं है और जो लोग C++ 14 (मेरे जैसे) के रूप में कॉन्टेक्सप्रस ऑब्जेक्ट्स लिखते हैं, वे जानते हैं कि वे अच्छे जवाब के लिए –