2015-10-06 15 views
11

चलो कहते हैं कि मेरे पास है चलो एक समारोह की तरह:आकार() std :: सरणी सूचक की constexpr संदर्भ में

int test(std::array<char, 8>* data) { 
    char buffer[data->size() * 2]; 

    [... some code ...] 
} 

स्पष्ट रूप से बफर के आकार संकलन समय पर मूल्यांकन किया जा सकता: डेटा 8 के एक constexpr आकार की है तत्व, 8 * 2 = 16 बाइट्स।

हालांकि, जब -Wall, -pedantic और -std=c++11 साथ संकलन मैं कुख्यात त्रुटि मिलती है:

warning: variable length arrays are a C99 feature [-Wvla-extension]

जो मेरा मानना ​​है कि बनाता है भावना: array::size()constexpr है, लेकिन यह अभी भी एक तरीका है, और हम ऊपर समारोह में अभी भी एक पॉइंटर को हटाना है, जो constexpr नहीं है।

अगर मैं की तरह कुछ प्रयास करें:

int test(std::array<char, 8>& data) { 
    char buffer[data.size() * 2]; 
    [...] 
} 

gcc (कोशिश की संस्करण 5.2.0) खुश लगता है: कोई चेतावनी है।

लेकिन clang++ (3.5.1) के साथ मुझे अभी भी परिवर्तनीय लंबाई सरणी के बारे में शिकायत करने की चेतावनी मिलती है।

मेरे मामले में, मैं आसानी से test के हस्ताक्षर को नहीं बदल सकता, इसे एक सूचक लेना है। तो ... कुछ सवाल:

  1. सबसे अच्छा/सबसे मानक constexpr संदर्भ में एक std::arrayसूचक के आकार पाने के लिए तरीका क्या है?

  2. क्या पॉइंटर्स बनाम संदर्भों के साथ व्यवहार में अंतर अपेक्षित है? कौन सा कंपाइलर चेतावनी, gcc या clang के बारे में सही है?

+1

यह जानना क्यों 'size' एक स्थिर सदस्य कार्य नहीं है दिलचस्प होगा .. – dyp

+1

मैं भी जोड़ना चाहिए वहाँ शायद किसी तरह टेम्प्लेट के माध्यम से आकार पाने के लिए है कि, कुछ की तरह: ' टेम्पलेट std :: size_t arraysize (स्थिरांक std :: सरणी और सरणी) {वापसी एन; } ' जो ऊपर उपयोग किया जा सकता है। फिर भी ... क्या यह सही तरीका है? लगता है कि contorted। – rabexc

+0

मैं इसे सूचक मामले में विफल होने पर देख सकता था लेकिन तकनीकी रूप से संदर्भ मामले नहीं, सूचक 'शून्य' हो सकता है; निश्चित रूप से, यह वहां कुछ भी उपयोगी नहीं कर सकता है, लेकिन इसका मतलब यह भी है कि 'आकार' ठीक से परिभाषित नहीं है। यदि 'आकार' वर्चुअल था, तो मैं इसे दोनों पॉइंटर्स और संदर्भों से शिकायत कर सकता था (क्योंकि यह 'std :: array 'से प्राप्त एक प्रकार हो सकता है जिसमें समान आकार' कार्यान्वयन 'नहीं है), लेकिन यह स्पष्ट रूप से नहीं है यहां मामला – ShadowRanger

उत्तर

2

मैं नहीं जानता के बारे में 2.

लेकिन 1 के लिए, हम यह कर सकते हैं:

template<class T, size_t N> 
constexpr std::integral_constant<size_t, N> array_size(std::array<T, N> const&) { 
    return {}; 
} 
तो

:

void test(std::array<char, 8>* data) { 
    using size=decltype(array_size(*data)); 
    char buffer[size{}]; 
    (void)buffer; 
    // [... some code ...] 
} 
वैकल्पिक रूप से

:

template<class T, class U, size_t N> 
std::array<T,N> same_sized_array(std::array< U, N > const&) { 
    return {}; 
} 

void test(std::array<char, 8>* data) { 
    auto buffer = same_sized_array<char>(*data); 
    (void)buffer; 
    // [... some code ...] 
} 
अंत में

, एक सी ++ 14 सफाई:

template<class A> 
constexpr const decltype(array_size(std::declval<A>())) array_size_v = {}; 

void test3(std::array<char, 8>* data) { 
    char buffer[array_size_v<decltype(*data)>]; 
    (void)buffer; 
    // [... some code ...] 
} 

Live example

+0

'कॉन्स्टेक्स कॉन्स' मेरे लिए थोड़ा अनावश्यक लगता है .. – dyp

+0

@dyp अगर आप चाहते हैं तो मैं अस्थिर जोड़ सकता हूं?;) – Yakk

0

अच्छा पुराना सी तरीका परिभाषित किया जाएगा, लेकिन सी ++ में const int या सी ++ 11 constexpr है। तो अगर आप चाहते हैं संकलक पता है कि सरणी के आकार एक संकलन समय निरंतर, सबसे पोर्टेबल (*) जिस तरह से यह सुनिश्चित करने के लिए होगा होने के लिए एक const या constexpr:

#include <iostream> 
#include <array> 

const size_t sz = 8; // constexpr size_t sz for c++11 

int test(std::array<char, sz>* data) { 
    char buffer[sz * 2]; 

    buffer[0] = 0; 
    return 0; 
} 
int main() 
{ 
    std::array<char, sz> arr = { { 48,49,50,51,52,53,54,55 } }; 
    int cr = test(&arr); 
    std::cout << cr << std::endl; 
    return 0; 
} 

यह एक चेतावनी के बिना संकलित , क्लैंग 3.4 के तहत -Wall -pedantic के साथ भी।1

दूसरे प्रश्न के लिए, मैं कल्पना नहीं कर सकते क्यों जीसीसी संकेत और refs यहाँ के बीच कि फर्क। या तो यह जिसका आकार है एक निरंतर एक निरंतर अभिव्यक्ति है एक std::array पर कि size() विधि निर्धारित कर सकते हैं - और यह दोनों के लिए अनुमति चाहिए - या यह नहीं कर सकते हैं - और यह दोनों पर एक ही चेतावनी फेंकना चाहिए। लेकिन यह न केवल कंपाइलर से संबंधित है, बल्कि मानक पुस्तकालय कार्यान्वयन भी करता है।

वास्तविक समस्या यह है कि प्री-सी ++ 11 std :: array मानक लाइब्रेरी का हिस्सा नहीं था, और constexpr को केवल C++ 11 से परिभाषित किया गया है। तो पूर्व सी ++ 11 मोड में, दोनों संकलक प्रक्रिया std :: एक विस्तार के रूप सरणी, लेकिन वहाँ size विधि के लिए कोई रास्ता नहीं एक निरंतर expr होने के लिए अपनी वापसी मूल्य घोषित करने के लिए है। यह बताता है कि क्लैंग (और एक सूचक का सामना करने वाला जीसीसी) चेतावनी को छोड़ देता है।

लेकिन आप C++ 11 मोड (-std=c++11) में मूल कोड संकलन यदि आप कोई चेतावनी नहीं होनी चाहिए, क्योंकि मानक एक std::array पर size() विधि एक constexpr होने की आवश्यकता है।

(*) प्रश्न सर्वोत्तम/सबसे मानक है; मैं यह नहीं कह सकते सबसे अच्छा तरीका है क्या, और मैं या तो सबसे मानक को परिभाषित नहीं कर सकते, तो मैं अगर मैं गैर सी ++ 11 compilers पर पोर्टेबिलिटी समस्याओं से बचना चाहते थे कि मैं क्या करने के लिए प्रयोग करेंगे चिपके रहते हैं।

+0

* "लेकिन यदि आप सी ++ 11 मोड (' -std = C++ 11') में मूल कोड संकलित करते हैं तो आपको कोई चेतावनी नहीं होनी चाहिए, क्योंकि मानक को std :: array पर 'size() 'विधि की आवश्यकता होती है एक 'constexpr' होने के लिए। "* एक' constexpr' (सदस्य) फ़ंक्शन को कॉल करते समय निरंतर अभिव्यक्ति उत्पन्न करने की आवश्यकता नहीं है। – dyp

+0

@dyp: मेरे लिए, और [cppreference] के लिए (http://en.cppreference.com/w/cpp/language/constexpr) * [t] वह 'constexpr' निर्दिष्टकर्ता घोषित करता है कि मूल्य का मूल्यांकन करना संभव है संकलन समय पर समारोह या चर *। तो कोई पैरामीटर * है * के साथ एक 'constexpr' फ़ंक्शन * आवश्यक है जो कुछ भी इस्तेमाल किया जा सकता है जहां एक कट्टरपंथी स्थिर हो सकता है। यदि यह पैरामीटर लेता है, तो ऐसा करने की आवश्यकता होती है यदि उसके पैरामीटर लगातार अभिव्यक्ति होते हैं। –

+1

यहां एक उदाहरण दिया गया है: 'struct foo {int i; constexpr int बार() {वापसी i; }}; int मुख्य() {foo f {rand()}; constexpr ऑटो एक्स = f.bar(); } ' – dyp

0

क्या अपने पैरामीटर का decltype पर std::tuple_size का उपयोग कर के बारे में?

void test(std::array<char, 8>* data) { 
    using data_type = std::remove_pointer<decltype(data)>::type; 
    char buffer[std::tuple_size<data_type>::value * 2]; 
    static_assert(sizeof buffer == 16, "Ouch"); 
    // [... some code ...] 
} 
संबंधित मुद्दे