2013-02-05 13 views
6

वहाँ कई अच्छे कारणों, पसंद करते हैं बजायऐरे गिनती जो ओडीआर-उपयोग नहीं करता है?

#include <cstdlib> 

template<typename T, std::size_t N> 
constexpr std::size_t ARRAY_COUNT_FUNC(T (&arr)[N]) { return N; } 

#define ARRAY_COUNT_MACRO(arr) (sizeof(arr)/sizeof(*arr)) 

एक महत्वपूर्ण अंतर यह है कि जब एक सूचक (एक सरणी नहीं) ARRAY_COUNT_MACRO को पारित कर दिया है, यह चुपचाप एक बेकार जवाब देता है लेकिन ARRAY_COUNT_FUNC पर एक ही तर्क को गुजरने से गलती को इंगित करने वाला एक कंपाइलर त्रुटि उत्पन्न होगी।

लेकिन मैक्रो के पास एक फायदा है: इसका तर्क अनचाहे है।

#include <utility> 
struct S { 
    int member_array[5]; 
}; 

// OK: 
std::size_t count1 = ARRAY_COUNT_MACRO(std::declval<S&>().member_array); 

// ERROR: std::declval is odr-used! 
std::size_t count2 = ARRAY_COUNT_FUNC(std::declval<S&>().member_array); 

क्या दोनों एक साथ लाभ के साथ एक और दृष्टिकोण है? I. ई।, कुछ ऐसा जो संकलन त्रुटि का कारण बनता है यदि तर्क एक सरणी नहीं है, और इसके तर्क का उपयोग नहीं करता है।

उत्तर

6

here वर्णित अनुसार, क्रोमियम परियोजना से बेमिसाल रूप से फट गया।

#include <utility> 
#include <cstdlib> 

template<typename T, std::size_t N> 
constexpr std::size_t ARRAY_COUNT_FUNC(T (&arr)[N]) { return N; } 

#define ARRAY_COUNT_MACRO(arr) (sizeof(arr)/sizeof(*arr)) 

// Template for typesafey goodness. 
template <typename T, size_t N> 
char (&ArraySizeHelper(T (&array)[N]))[N]; 
// sizeof to avoid actually calling the function. 
#define arraysize(array) (sizeof(ArraySizeHelper(array))) 

struct S { 
    int member_array[5]; 
}; 

int main() 
{ 

    // OK: 
    std::size_t count1 = ARRAY_COUNT_MACRO(std::declval<S&>().member_array); 

    // ERROR: std::declval is odr-used! 
    //std::size_t count2 = ARRAY_COUNT_FUNC(std::declval<S&>().member_array); 

    // OK: 
    std::size_t count2 = arraysize(std::declval<S&>().member_array); 

    // ERROR: 
    // int * p; 
    // std::size_t count3 = arraysize(p); 
} 
+3

भगवान ही जानता है कि कैसे बहुत पहले विचार पहले रची गई थी, लेकिन [माइक्रोसॉफ्ट मूलतः एक ही एल्गोरिथ्म का उपयोग करता] (http://blogs.msdn.com/b/the1/archive/2004/05 /07/128242.aspx) उनके '_countof (ar) 'मैक्रो के लिए, और कम से कम '04 के बाद से है। संभावना है कि वे शायद * unshamelessly * किसी और से इसे फट गया। – WhozCraig

2

... और फिर मुझे याद है <type_traits> एक std::is_array टेम्पलेट है। एक अन्य समाधान:

#include <type_traits> 

template<typename T> 
constexpr auto ArrayCountImpl(std::nullptr_t) 
    -> typename std::enable_if<std::is_array<typename 
            std::remove_reference<T>::type>::value, 
           std::size_t>::type 
{ return std::extent<typename std::remove_reference<T>::type>::value; } 

template<typename T> 
std::size_t ArrayCountImpl(...) 
{ static_assert(!std::is_same<T,T>::value, 
       "Argument type is not an array"); } 

#define ARRAY_COUNT_MACRO_2(arr) (ArrayCountImpl<decltype(arr)>(nullptr)) 
संबंधित मुद्दे