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

重要な違いの1つは、ポインタ(配列ではない)がに渡されるとARRAY_COUNT_MACRO、役に立たない答えが黙って返されることですが、同じ引数をに渡すとARRAY_COUNT_FUNC、間違いを指摘するコンパイラエラーが発生します。

しかし、マクロには1つの利点があります。それは、その引数が評価されていないことです。

#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しないもの。

4

2 に答える 2

6

ここで説明するように、Chromiumプロジェクトから恥知らずに引き裂かれました。

#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);
}
于 2013-02-05T17:23:28.497 に答える
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))
于 2013-02-05T17:46:10.607 に答える