有几个很好的理由去选择
#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);
是否有另一种方法可以同时发挥两者的优势?即,如果参数不是数组,并且不 odr-use 其参数,则会导致编译错误。
最佳答案
无耻地从 Chromium 项目中敲诈,如所述 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);
}
关于c++ - 不使用 odr 的数组计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14713068/