2017-08-03 11 views
10

टीएल; डीआर: क्या निम्नलिखित हमेशा सुरक्षित है? या क्या यह अपरिभाषित, अनिर्दिष्ट या कार्यान्वयन परिभाषित व्यवहार का कारण बनता है?क्या मैं हमेशा एक निश्चित (स्कॉप्ड) गणना के अंतर्निहित प्रकार में सुरक्षित रूप से डाल सकता हूं?

template <class T> 
using ut = typename std::underlying_type<T>::type; 

template <typename E> ut<E> identity(ut<E> value) { 
    return static_cast<ut<E>>(static_cast<E>(value)); 
} 

अगर मैं एक scoped गणन है मैं हमेशा अंतर्निहित इसे टाइप कास्ट कर सकते हैं:

#include <cassert>    // if you want to follow along 
#include <initializer_list> // copy everything and remove my text 

enum class priority : int { 
    low = 0, 
    normal = 1, 
    high = 2 
}; 

// works fine 
int example = static_cast<int>(priority::high); 

सभी मूल्यों कि गणन में परिभाषित कर रहे हैं के लिए मैं भी उम्मीद कर सकते हैं कि मैं मिल वापस मूल्य:

constexpr priority identity_witness(priority p) { 
    return static_cast<priority>(static_cast<int>(p)); 
} 

void test_enum() { 
    for (const auto p : {priority::low, priority::normal, priority::high}) { 
    assert(p == identity_witness(p)); 
    } 
} 

N3337 के अनुसार (सी ++ 11), 5.2.9 स्टेटिक डाली [expr.static.cast] § 9-10 इस पंख है ई:

  1. एक दायरे वाला गणना प्रकार (7.2) का मान स्पष्ट रूप से एक अभिन्न प्रकार में बदला जा सकता। यदि मूल मान निर्दिष्ट प्रकार से प्रदर्शित किया जा सकता है तो मान अपरिवर्तित है। ...
  2. अभिन्न या गणना प्रकार का एक मूल्य स्पष्ट रूप से एक गणना प्रकार में परिवर्तित किया जा सकता है। मान मूल रूप से गणना मूल्यों (7.2) की सीमा के भीतर है, तो मान अपरिवर्तित है। ...

हालांकि, मैं इसका उल्टा में दिलचस्पी रखता हूँ। क्या होता है अगर मैं एक enum और वापस अंतर्निहित प्रकार पर डाल दिया?

constexpr int identity_witness(int i) { 
    return static_cast<int>(static_cast<priority>(i)); 
} 

void test_int() { 
    for (const auto p : {0, 1, 2, 3, 4, 5}) { 
    assert(p == identity_witness(p)); 
    } 
} 

int main() { 
    test_enum(); 
    test_int(); 
} 

यह संकलित करता है तथा ठीक काम करता है, के बाद से अंतर्निहित प्रकार के लिए एक static_cast बिल्कुल (शायद) स्मृति परिवर्तन नहीं होगा। हालांकि, मानक का कहना है कि व्यवहार अनिर्दिष्ट है यदि मूल्य श्रेणी में नहीं है:

  1. [जारी रखा] अन्यथा, जिसके परिणामस्वरूप मूल्य अनिर्दिष्ट है (और में नहीं हो सकता है वह सीमा)।

रेंज enumerations के मेरे लिए स्पष्ट नहीं है। 7.2§7 के मुताबिक, "गणना के मूल्य अंतर्निहित प्रकार के मूल्य हैं" यदि गणना के अंतर्निहित प्रकार को ठीक किया गया है। इसलिए, किसी भी std::underlying_type<my_enumeration_type> के लिए, उपरोक्त संपत्ति को पकड़ना चाहिए।

क्या यह तर्क मानक में कुछ अजीब खंड को याद करता है, या गणना के अंतर्निहित प्रकार में एक कलाकार को अपरिभाषित या अनिर्दिष्ट व्यवहार का कारण बन सकता है?

+2

अच्छा सवाल, और मुझे उम्मीद है कि उत्तर 'हां हमेशा सुरक्षित' है क्योंकि मैं थोड़ी देर के लिए अंतर्निहित प्रकार पर सहायक कास्टिंग का उपयोग कर रहा हूं, इसे और अधिक विचार किए बिना: पी – stijn

+0

@stijn तो करें मैं, एक ही उपयोग के मामले के साथ। यह सिर्फ एक कोड समीक्षा के दौरान आया था। 7.2 और 5.2.9 के अनुसार, यह _should_ ठीक हो जाएगा, लेकिन मैं किसी और द्वारा दूसरी राय प्राप्त करना चाहता हूं (या अगले हफ्ते के अंत में मानक फिर से पढ़ना)। – Zeta

उत्तर

3

मानक आपको लगता है कि किसी दिए गए प्रकार के मनमाना अभिन्न मूल्यों का उपयोग उस प्रकार के लिए निर्धारित गणना के मान के रूप में करने के लिए किया जाता है, भले ही उन्हें गणना मान के रूप में नामित न किया जाए। 5.2.9.10 में चेतावनी संभवतः निश्चित अंतर्निहित प्रकार के बिना गणना को सीमित करने के लिए है। मानक एक निश्चित प्रकार के गणना मूल्यों की "सीमा" को परिभाषित नहीं करता है क्योंकि गणना के मूल्यों से कुछ भी अलग है। विशेष रूप से, यह कहता है:

एक ऐसी गणना को परिभाषित करना संभव है जिसमें उसके किसी भी गणक द्वारा परिभाषित मूल्य नहीं हैं।

तो "गणना मूल्यों की सीमा के भीतर है" को "गणना मूल्यों में से एक" के अलावा कुछ भी नहीं समझा जा सकता है। गणना के मूल्यों की सीमा की कोई अन्य परिभाषा नहीं है।

तो आप निश्चित अंतर्निहित प्रकार के साथ गणना के लिए सुरक्षित हैं। अवांछित गणनाओं के लिए, यदि आप बिट्स की सुरक्षित संख्या से चिपके रहते हैं तो आप केवल सुरक्षित हैं।

+0

क्या गणनाकर्ताओं ने अभी सीमा में स्थिरांक नामित नहीं हैं? मुझे पूरा यकीन है कि सीमा अलग अवधारणा है, लेकिन इस समय जांच नहीं कर सकती है। – StoryTeller

+0

@StoryTeller शब्द "रेंज" का प्रयोग एक (अनियमित) गणना के मूल्यों को परिभाषित करने में किया जाता है, लेकिन "सीमा" वाले गणित के अर्थ में नहीं। और इसका उपयोग टाइप किए गए अंकन के लिए बिल्कुल नहीं किया जाता है। – Sneftel

+0

ठीक है, अब मुझे जांच करने का मौका मिला था। सी ++ 17 यह कहता है: ["एक गणना के लिए जिसका अंतर्निहित प्रकार तय किया गया है, गणना के मूल्य अंतर्निहित प्रकार के मान हैं।"] (Https://timsong-cpp.github.io/cppwp/ n4659/dcl.enum # 8)। यह गणनाओं पर भी लागू होता है, साथ ही साथ कोई भी संख्या नहीं। मुझे यकीन नहीं है कि सी ++ 11 में एक ही शब्द है। – StoryTeller

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

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