2013-02-05 26 views
6

Có nhiều lý do tốt để thíchSố lượng mảng không sử dụng odr?

#include <cstdlib> 

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

hơn

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

Một khác biệt quan trọng là khi một con trỏ (không phải là một mảng) được chuyển đến ARRAY_COUNT_MACRO, nó âm thầm trả về một câu trả lời vô ích, nhưng chuyển cùng một đối số cho ARRAY_COUNT_FUNC sẽ gây ra lỗi trình biên dịch chỉ ra lỗi.

Nhưng macro có một lợi thế: đối số của nó không được đánh giá.

#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); 

Có cách tiếp cận nào khác có lợi ích của cả hai? I. e., Cái gì đó gây ra một lỗi biên dịch nếu đối số không phải là một mảng và không sử dụng đối số của nó.

Trả lời

6

Không biết gì bị gạt khỏi dự án Chromium, như được mô tả 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

Chúa chỉ biết được ý tưởng trước đây được ấp trứng bao lâu, nhưng [Microsoft sử dụng cơ bản cùng một thuật toán] (http://blogs.msdn.com/b/the1/archive/2004/05 /07/128242.aspx) cho macro '_countof (ar)' của chúng và ít nhất là '04 '. Cơ hội là họ có lẽ * không biết ơn * xé nó ra khỏi người khác. – WhozCraig

2

... Và sau đó tôi nhớ <type_traits> có mẫu std::is_array. Một giải pháp khác:

#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)) 
Các vấn đề liên quan