2015-06-01 6 views
13

में कनवर्ट करना रोकें निम्नलिखित कोड क्लैंग ++ में क्यों संकलित करते हैं?uint64_t को uint16_t

क्या ऐसा होने से रोकने के लिए कोई सी ++ झंडे हैं - मैं संकलक को एक त्रुटि फेंकना चाहता हूं क्योंकि मैं std :: uint64_t को स्वीकार करने वाले फ़ंक्शन के लिए एक std :: uint64_t को गुजर रहा हूं।

#include <cstdint> 
using namespace std; 

void foo(uint16_t x) { 
} 

int main() { 
    uint64_t x = 10000; 
    foo(x); 
    return 0; 
} 
+2

क्यों नहीं करना चाहिए ' यह नहीं है? –

+3

सी ++ में रूपांतरणों को संक्षिप्त करने की अनुमति है, और हस्ताक्षरित संकुचित रूपांतरण अच्छी तरह से परिभाषित हैं –

+12

'-Werror = रूपांतरण' जोड़ना आपके उदाहरण को संकलित नहीं करेगा। – Praetorian

उत्तर

33

आप सी में एक समारोह को हटा सकते हैं ++ 11

void foo(uint64_t) = delete; 

यह समारोह अधिभार संकल्प पर हस्ताक्षर जोड़कर काम करता है, और अगर यह एक बेहतर मैच था, एक त्रुटि उत्पन्न होती है। आप भी इसे सामान्य ही आप मूल हस्ताक्षर कर देता है

template <class T> void foo(T&&) = delete; 
+0

इस प्रश्न के प्रति उत्तरदायी कैसे है? –

+5

उसने पूछा कि इसे कैसे होने से रोका जाए और इससे प्रभावी रूप से इसे रोका जा सकेगा। – Puppy

+2

@ जॉन बोलिंगर: दिया गया कार्यक्रम इस जोड़े के साथ संकलित करने में विफल रहेगा, है ना? – Guvante

9

तुम भी एक SFINAE वापसी पैरामीटर के रूप में enable_if उपयोग कर सकते हैं

#include <iostream> 
#include <cstdint> 
#include <type_traits> 

template<typename T> 
typename std::enable_if<std::is_same<T, uint16_t>::value>::type 
foo(T x) 
{ 
    std::cout << "uint16_t" << std::endl; 
} 

template<typename T> 
typename std::enable_if<!std::is_same<T, uint16_t>::value>::type 
foo(T x) 
{ 
    std::cout << "rest" << std::endl; 
} 

int main() { 
    uint16_t x = 10000; 
    uint64_t y = 100000; 
    foo(x); // picks up uint16_t version 
    foo(y); // picks up anything else, but NOT uint16_t 
    return 0; 
} 

इस तरह से आप एक अधिभार कि uint16_t साथ विशिष्ट रूप से संबंधित हो सकता है में, और एक और अधिभार जो किसी और चीज़ से संबंधित है।

+0

यह अच्छा है लेकिन यह रूपांतरणों को चौड़ा करने से रोकता है (जैसा कि अन्य उत्तर करता है)। यह अच्छा होगा अगर फ़ंक्शन उदाहरण के लिए 'uint8_t' मान स्वीकार कर सके, और हो सकता है कि यहां तक ​​कि शाब्दिक भी जिसका मूल्य' uint16_t' में फिट हो। किसी ने 'std :: common_type' [यहां] (http://stackoverflow.com/a/16945743/1505939) का उपयोग करने का सुझाव दिया है, हालांकि मुझे नहीं लगता कि 'int' –

+0

पर पूर्णांक पदोन्नति के कारण' uint16_t' के लिए काम करेगा। MattMcNabb हम्म, यह थोड़ा और मुश्किल लगता है, और यह वास्तव में दिलचस्प है: पैरामीटर में "फिट" कुछ भी स्वीकार करने के लिए कैसे। खैर, एक "रास्ता" है: ब्रूट फोर्स, टेम्पलेट को स्पष्ट रूप से निर्दिष्ट करें, जैसे 'foo (x); '। हालांकि बहुत सुंदर नहीं है। – vsoftco

5

आप शायद रूपांतरण चौड़ा करने की अनुमति देते हैं, लेकिन संकुचन रूपांतरण ना करे के लिए, चाहते हैं:

void foo(uint16_t x) { 
} 

template <class T> 
void foo(const T&& t) 
{ 
    return foo(uint16_t{t}); 
} 

यह uint16_t खुद को छोड़कर सभी प्रकार के बलों सूची-प्रारंभ है, जिससे रूपांतरणों को सीमित करने मनाही के माध्यम से जाना।

यदि आपके पास पहले से ही कई अधिभार हैं, तो यह बहुत अच्छा काम नहीं करता है।

+0

दुर्भाग्य से एक त्रुटि के परिणामस्वरूप संकुचित करने की आवश्यकता नहीं है, उदाहरण के लिए देखें। http://stackoverflow.com/q/28466069/3093378। उदाहरण के लिए, यह काम करता है: http://ideone.com/DHqBYL। शायद मुझे कुछ याद आ रही है। – vsoftco

+0

@ vsoftco "यदि तत्व को 'टी' में परिवर्तित करने के लिए एक संकुचित रूपांतरण (नीचे देखें) आवश्यक है, तो प्रोग्राम 8.5 बी – Barry

+0

@ बारी हां से बीमार गठित है, हालांकि यह बीमार है, हालांकि संकलक नहीं है एक त्रुटि उत्सर्जित करने के लिए आवश्यक है। और वास्तव में कार्यक्रम संकलित करता है। – vsoftco

6

यहाँ एक समाधान है कि रूपांतरण चौड़ा करने की अनुमति है और सीमित करने वाले रोका जा सके है:

#include <cstdint> 
#include <type_traits> 

void foo(uint16_t x) { 
} 

template <class T> 
typename std::enable_if<sizeof(uint16_t) < sizeof(T)>::type foo(const T& t) = delete; 

int main() { 
    uint64_t x = 10000; 
    uint16_t y = 10000; 
    uint8_t z = 100; 
    // foo(x); // ERROR: narrowing conversion 
    foo(y); // OK: no conversion 
    foo(z); // OK: widening conversion 
    return 0; 
} 

मामले में आप भी हस्ताक्षर किए प्रकार के तर्क के साथ कॉल अस्वीकृत करने के लिए चाहते हैं (पर हस्ताक्षर किए और अहस्ताक्षरित प्रकार के बीच रूपांतरण नहीं है " दोषरहित "), तो आपको निम्न घोषणा के बजाय इस्तेमाल कर सकते हैं:

#include <cstdint> 
#include <type_traits> 

void foo(uint16_t x) { 
} 

template <class T> 
typename std::enable_if<(sizeof(uint16_t) < sizeof(T)) || 
         (std::is_signed<T>::value != std::is_signed<uint16_t>::value) 
         >::type 
foo(const T& t) = delete; 

int main() { 
    uint64_t u64 = 10000; 
    uint16_t u16 = 10000; 
    uint8_t u8 = 100; 
    int64_t s64 = 10000; 
    int16_t s16 = 10000; 
    int8_t s8 = 100; 

    //foo(u64); // ERROR: narrowing conversion 
    foo(u16); // OK: no conversion 
    foo(u8); // OK: widening conversion 
    //foo(s64); // ERROR: narrowing conversion AND signed/unsigned mismatch 
    //foo(s16); // ERROR: signed/unsigned mismatch 
    //foo(s8); // ERROR: signed/unsigned mismatch 

    return 0; 
} 
3

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

एक "परियोजना/संकलन स्तर" पर आप इन परिवर्तनों के बारे में चेतावनी देने के लिए इस ध्वज जोड़ सकते हैं:

-Wconversion 

या यदि आप सीधे पसंद करते हैं उन्हें त्रुटियों के रूप में इलाज:

-Werror=conversion 
+1

ध्यान दें कि यह हस्ताक्षर किए गए 'int16_t' से हस्ताक्षरित' uint16_t' तक रूपांतरण के बारे में चेतावनी नहीं देगा (जीसीसी 4.9.2 में परीक्षण किया गया है, जो भी अमान्य मान को फ़ंक्शन में पारित कर सकता है। आप हस्ताक्षर में परिवर्तनों का पता लगाने के लिए '-Wsign-conversion' (या'-werror = sign-conversion') जोड़ सकते हैं। –

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