这个宏可以转换为函数吗?

发布于 2024-07-05 03:14:52 字数 241 浏览 5 评论 0原文

在重构代码并摆脱所有那些我们现在被教导讨厌的 #define 的同时,我遇到了用于计算结构中元素数量的美丽:

#define STRUCTSIZE(s) (sizeof(s) / sizeof(*s))

它非常有用,但可以将其转换为内联函数吗或模板?

好吧,ARRAYSIZE 是一个更好的名字,但这是遗留代码(不知道它来自哪里,它至少有 15 年的历史)所以我“按原样”粘贴它。

While refactoring code and ridding myself of all those #defines that we're now taught to hate, I came across this beauty used to calculate the number of elements in a structure:

#define STRUCTSIZE(s) (sizeof(s) / sizeof(*s))

Very useful as it is but can it be converted into an inline function or template?

OK, ARRAYSIZE would be a better name but this is legacy code (no idea where it came from, it's at least 15 years old) so I pasted it 'as is'.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

夏九 2024-07-12 03:14:52

Windows 特定:

CRT 提供的宏_countof() 正是用于此目的。

MSDN 上的文档链接

Windows specific:

There is the macro _countof() supplied by the CRT exactly for this purpose.

A link to the doc at MSDN

你曾走过我的故事 2024-07-12 03:14:52

对于 C99 风格的可变长度数组,纯宏方法 (sizeof(arr) / sizeof(arr[0])) 似乎是唯一可行的方法。

For C99-style variable-length arrays, it appears that the pure macro approach (sizeof(arr) / sizeof(arr[0])) is the only one that will work.

遇见了你 2024-07-12 03:14:52

正如 JohnMcG 的回答,但

缺点是您将在二进制文件中为每个类型名、大小组合都有一个副本。

这就是为什么您将其设为内联模板函数。

As JohnMcG's answer, but

Disadvantage is you will have a copy of this in your binary for every Typename, Size combination.

That's why you'd make it an inline template function.

南渊 2024-07-12 03:14:52

该宏的名称非常具有误导性 - 如果将数组的名称作为宏参数传入,则宏中的表达式将返回数组中的元素数量。

对于其他类型,如果类型是指针,您将得到或多或少毫无意义的东西,否则您将收到语法错误。

通常该宏的名称类似于 NUM_ELEMENTS() 或其他名称以表明其真正的用处。 在 C 中不可能用函数替换宏,但在 C++ 中可以使用模板。

我使用的版本基于 Microsoft 的 winnt.h 标头中的代码(如果发布此代码片段超出了合理使用范围,请告诉我):

//
// Return the number of elements in a statically sized array.
//   DWORD Buffer[100];
//   RTL_NUMBER_OF(Buffer) == 100
// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc.
//
#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))

#if defined(__cplusplus) && \
    !defined(MIDL_PASS) && \
    !defined(RC_INVOKED) && \
    !defined(_PREFAST_) && \
    (_MSC_FULL_VER >= 13009466) && \
    !defined(SORTPP_PASS)
//
// RtlpNumberOf is a function that takes a reference to an array of N Ts.
//
// typedef T array_of_T[N];
// typedef array_of_T &reference_to_array_of_T;
//
// RtlpNumberOf returns a pointer to an array of N chars.
// We could return a reference instead of a pointer but older compilers do not accept that.
//
// typedef char array_of_char[N];
// typedef array_of_char *pointer_to_array_of_char;
//
// sizeof(array_of_char) == N
// sizeof(*pointer_to_array_of_char) == N
//
// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T);
//
// We never even call RtlpNumberOf, we just take the size of dereferencing its return type.
// We do not even implement RtlpNumberOf, we just decare it.
//
// Attempts to pass pointers instead of arrays to this macro result in compile time errors.
// That is the point.
//
extern "C++" // templates cannot be declared to have 'C' linkage
template <typename T, size_t N>
char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N];

#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A)))

//
// This does not work with:
//
// void Foo()
// {
//    struct { int x; } y[2];
//    RTL_NUMBER_OF_V2(y); // illegal use of anonymous local type in template instantiation
// }
//
// You must instead do:
//
// struct Foo1 { int x; };
//
// void Foo()
// {
//    Foo1 y[2];
//    RTL_NUMBER_OF_V2(y); // ok
// }
//
// OR
//
// void Foo()
// {
//    struct { int x; } y[2];
//    RTL_NUMBER_OF_V1(y); // ok
// }
//
// OR
//
// void Foo()
// {
//    struct { int x; } y[2];
//    _ARRAYSIZE(y); // ok
// }
//

#else
#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A)
#endif

#ifdef ENABLE_RTL_NUMBER_OF_V2
#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A)
#else
#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A)
#endif

//
// ARRAYSIZE is more readable version of RTL_NUMBER_OF_V2, and uses
// it regardless of ENABLE_RTL_NUMBER_OF_V2
//
// _ARRAYSIZE is a version useful for anonymous types
//
#define ARRAYSIZE(A)    RTL_NUMBER_OF_V2(A)
#define _ARRAYSIZE(A)   RTL_NUMBER_OF_V1(A)

另外,Matthew Wilson 的书“Imperfect C++”对这里发生的情况有很好的处理(第 14.3 节) -第211-213页-数组和指针-dimensionof())。

The macro has a very misleading name - the expression in the macro will return the number of elements in an array if an array's name is passed in as the macro parameter.

For other types you'll get something more or less meaningless if the type is a pointer or you'll get a syntax error.

Usually that macro is named something like NUM_ELEMENTS() or something to indicate its true usefulness. It's not possible to replace the macro with a function in C, but in C++ a template can be used.

The version I use is based on code in Microsoft's winnt.h header (please let me know if posting this snippet goes beyond fair use):

//
// Return the number of elements in a statically sized array.
//   DWORD Buffer[100];
//   RTL_NUMBER_OF(Buffer) == 100
// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc.
//
#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))

#if defined(__cplusplus) && \
    !defined(MIDL_PASS) && \
    !defined(RC_INVOKED) && \
    !defined(_PREFAST_) && \
    (_MSC_FULL_VER >= 13009466) && \
    !defined(SORTPP_PASS)
//
// RtlpNumberOf is a function that takes a reference to an array of N Ts.
//
// typedef T array_of_T[N];
// typedef array_of_T &reference_to_array_of_T;
//
// RtlpNumberOf returns a pointer to an array of N chars.
// We could return a reference instead of a pointer but older compilers do not accept that.
//
// typedef char array_of_char[N];
// typedef array_of_char *pointer_to_array_of_char;
//
// sizeof(array_of_char) == N
// sizeof(*pointer_to_array_of_char) == N
//
// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T);
//
// We never even call RtlpNumberOf, we just take the size of dereferencing its return type.
// We do not even implement RtlpNumberOf, we just decare it.
//
// Attempts to pass pointers instead of arrays to this macro result in compile time errors.
// That is the point.
//
extern "C++" // templates cannot be declared to have 'C' linkage
template <typename T, size_t N>
char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N];

#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A)))

//
// This does not work with:
//
// void Foo()
// {
//    struct { int x; } y[2];
//    RTL_NUMBER_OF_V2(y); // illegal use of anonymous local type in template instantiation
// }
//
// You must instead do:
//
// struct Foo1 { int x; };
//
// void Foo()
// {
//    Foo1 y[2];
//    RTL_NUMBER_OF_V2(y); // ok
// }
//
// OR
//
// void Foo()
// {
//    struct { int x; } y[2];
//    RTL_NUMBER_OF_V1(y); // ok
// }
//
// OR
//
// void Foo()
// {
//    struct { int x; } y[2];
//    _ARRAYSIZE(y); // ok
// }
//

#else
#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A)
#endif

#ifdef ENABLE_RTL_NUMBER_OF_V2
#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A)
#else
#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A)
#endif

//
// ARRAYSIZE is more readable version of RTL_NUMBER_OF_V2, and uses
// it regardless of ENABLE_RTL_NUMBER_OF_V2
//
// _ARRAYSIZE is a version useful for anonymous types
//
#define ARRAYSIZE(A)    RTL_NUMBER_OF_V2(A)
#define _ARRAYSIZE(A)   RTL_NUMBER_OF_V1(A)

Also, Matthew Wilson's book "Imperfect C++" has a nice treatment of what's going on here (Section 14.3 - page 211-213 - Arrays and Pointers - dimensionof()).

贪恋 2024-07-12 03:14:52

是的,它可以在 C++ 中制作一个模板

template <typename T>
size_t getTypeSize()
{
   return sizeof(T)/sizeof(*T);
}

来使用:

struct JibbaJabba
{
   int int1;
   float f;
};

int main()
{
    cout << "sizeof JibbaJabba is " << getTypeSize<JibbaJabba>() << std::endl;
    return 0;
}

请参阅上面或下面的 BCS 帖子,了解使用一些轻型模板元编程在编译时对类执行此操作的很酷的方法。

Yes it can be made a template in C++

template <typename T>
size_t getTypeSize()
{
   return sizeof(T)/sizeof(*T);
}

to use:

struct JibbaJabba
{
   int int1;
   float f;
};

int main()
{
    cout << "sizeof JibbaJabba is " << getTypeSize<JibbaJabba>() << std::endl;
    return 0;
}

See BCS's post above or below about a cool way to do this with a class at compile time using some light template metaprogramming.

哆啦不做梦 2024-07-12 03:14:52

xtofl 具有查找数组大小的正确答案。 不需要宏或模板来查找结构的大小,因为 sizeof() 应该做得很好。

我同意预处理器是邪恶的,但是有它是最不邪恶的替代方案的场合。

xtofl has the right answer for finding an array size. No macro or template should be necessary for finding the size of a struct, since sizeof() should do nicely.

I agree the preprocessor is evil, but there are occasions where it is the least evil of the alternatives.

救赎№ 2024-07-12 03:14:52

我认为这并不能真正计算出结构中元素的数量。 如果结构被压缩并且您使用了小于指针大小的东西(例如 32 位系统上的 char),那么您的结果是错误的。 另外,如果该结构包含一个结构,那么你也错了!

I don't think that that really does work out the number of elements in a structure. If the structure is packed and you used things smaller than the pointer size (such as char on a 32-bit system) then your results are wrong. Also, if the struct contains a struct you are wrong too!

是伱的 2024-07-12 03:14:52

我更喜欢 [BCS] 建议的枚举方法(在 可以吗宏可以转换为函数吗?

这是因为您可以在编译器期望编译时间常量的地方使用它。 该语言的当前版本不允许您使用函数结果作为编译时常量,但我相信这将出现在编译器的下一个版本中:

此方法的问题在于,与类一起使用时它不会生成编译时错误已重载“*”运算符(有关详细信息,请参阅下面的代码)。

不幸的是,“BCS”提供的版本没有完全按预期编译,所以这是我的版本:

#include <iterator>
#include <algorithm>
#include <iostream>


template<typename T>
struct StructSize
{
    private:    static T x;
    public:      enum { size = sizeof(T)/sizeof(*x)};
};

template<typename T>
struct StructSize<T*>
{
    /* Can only guarantee 1 item (maybe we should even disallow this situation) */
    //public:     enum { size = 1};
};

struct X
{
    int operator *();
};


int main(int argc,char* argv[])
{
    int data[]                                  = {1,2,3,4,5,6,7,8};
    int copy[ StructSize<typeof(data)>::size];

    std::copy(&data[0],&data[StructSize<typeof(data)>::size],©[0]);
    std::copy(©[0],©[StructSize<typeof(copy)>::size],std::ostream_iterator<int>(std::cout,","));

    /*
     * For extra points we should make the following cause the compiler to generate an error message */
    X   bad1;
    X   bad2[StructSize<typeof(bad1)>::size];
}

I prefer the enum method suggested by [BCS](in Can this macro be converted to a function?)

This is because you can use it where the compiler is expecting a compile time constant. The current version of the language does not let you use functions results for compile time consts but I believe this coming in the next version of the compiler:

The problem with this method is that it does not generate a compile time error when used with a class that has overloaded the '*' operator (see code below for details).

Unfortunately the version supplied by 'BCS' does not quite compile as expected so here is my version:

#include <iterator>
#include <algorithm>
#include <iostream>


template<typename T>
struct StructSize
{
    private:    static T x;
    public:      enum { size = sizeof(T)/sizeof(*x)};
};

template<typename T>
struct StructSize<T*>
{
    /* Can only guarantee 1 item (maybe we should even disallow this situation) */
    //public:     enum { size = 1};
};

struct X
{
    int operator *();
};


int main(int argc,char* argv[])
{
    int data[]                                  = {1,2,3,4,5,6,7,8};
    int copy[ StructSize<typeof(data)>::size];

    std::copy(&data[0],&data[StructSize<typeof(data)>::size],©[0]);
    std::copy(©[0],©[StructSize<typeof(copy)>::size],std::ostream_iterator<int>(std::cout,","));

    /*
     * For extra points we should make the following cause the compiler to generate an error message */
    X   bad1;
    X   bad2[StructSize<typeof(bad1)>::size];
}
小苏打饼 2024-07-12 03:14:52

简化@KTC,因为我们在模板参数中有数组的大小:

template<typename T, int SIZE>
int arraySize(const T(&arr)[SIZE])
{
    return SIZE;
}

缺点是您将在二进制文件中为每个类型名、大小组合都有一个副本。

Simplfying @KTC's, since we have the size of the array in the template argument:

template<typename T, int SIZE>
int arraySize(const T(&arr)[SIZE])
{
    return SIZE;
}

Disadvantage is you will have a copy of this in your binary for every Typename, Size combination.

屋顶上的小猫咪 2024-07-12 03:14:52
  • 函数,没有模板函数,是
  • 模板,我这么认为(但 C++
  • 模板不是我的事)

编辑:从 Doug 的代码中

template <typename T>
uint32_t StructSize()  // This might get inlined to a constant at compile time
{
   return sizeof(T)/sizeof(*T);
}

// or to get it at compile time for shure

class StructSize<typename T>
{
   enum { result = sizeof(T)/sizeof(*T) };
}

我被告知第二个不起作用。 OTOH 类似的东西应该是可行的,我只是没有使用足够的 C++ 来修复它。

有关编译时内容的 C++(和 D)模板页面

  • function, no template function, yes
  • template, I think so (but C++
  • templates are not my thing)

Edit: From Doug's code

template <typename T>
uint32_t StructSize()  // This might get inlined to a constant at compile time
{
   return sizeof(T)/sizeof(*T);
}

// or to get it at compile time for shure

class StructSize<typename T>
{
   enum { result = sizeof(T)/sizeof(*T) };
}

I've been told that the 2nd one doesn't work. OTOH something like it should be workable, I just don't use C++ enough to fix it.

A page on C++ (and D) templates for compile time stuff

ぇ气 2024-07-12 03:14:52

你的宏命名错误,它应该被称为 ARRAYSIZE。 它用于确定大小在编译时固定的数组中元素的数量。 这是一种可行的方法:

char foo[128]; // 实际上,你会
有一些常数或常数
表达式作为数组大小。

for( 无符号 i = 0; i < STRUCTSIZE(
富); ++i){}

使用起来有点脆弱,因为你可能会犯这个错误:

char* foo = new char[128];

for( 无符号 i = 0; i < STRUCTSIZE(
富); ++i){}

您现在将迭代 i = 0 到 < 1、然后把头发扯下来。

Your macro is misnamed, it should be called ARRAYSIZE. It is used to determine the number of elements in an array whos size is fixed at compile time. Here's a way it can work:

char foo[ 128 ]; // In reality, you'd
have some constant or constant
expression as the array size.

for( unsigned i = 0; i < STRUCTSIZE(
foo ); ++i ) { }

It's kind of brittle to use, because you can make this mistake:

char* foo = new char[128];

for( unsigned i = 0; i < STRUCTSIZE(
foo ); ++i ) { }

You will now iterate for i = 0 to < 1 and tear your hair out.

故事↓在人 2024-07-12 03:14:52

与模板类不同,模板函数的类型是自动推断的。 您可以更简单地使用它:

template< typename T > size_t structsize( const T& t ) { 
  return sizeof( t ) / sizeof( *t ); 
}


int ints[] = { 1,2,3 };
assert( structsize( ints ) == 3 );

但我确实同意它不适用于结构:它适用于数组。 所以我宁愿称之为 Arraysize :)

The type of a template function is inferred automatically, in contrast with that of a template class. You can use it even simpler:

template< typename T > size_t structsize( const T& t ) { 
  return sizeof( t ) / sizeof( *t ); 
}


int ints[] = { 1,2,3 };
assert( structsize( ints ) == 3 );

But I do agree it doesn't work for structs: it works for arrays. So I would rather call it Arraysize :)

折戟 2024-07-12 03:14:52

KTC 的解决方案很干净,但它不能在编译时使用,并且依赖于编译器优化来防止代码膨胀和函数调用开销。

可以使用仅编译时元函数计算数组大小,运行时成本为零。 BCS 走在正确的轨道上,但该解决方案是不正确的。

这是我的解决方案:

// asize.hpp
template < typename T >
struct asize; // no implementation for all types...

template < typename T, size_t N >
struct asize< T[N] > { // ...except arrays
    static const size_t val = N;
};

template< size_t N  >
struct count_type { char val[N]; };

template< typename T, size_t N >
count_type< N > count( const T (&)[N] ) {}

#define ASIZE( a ) ( sizeof( count( a ).val ) ) 
#define ASIZET( A ) ( asize< A >::val ) 

使用测试代码(使用 Boost.StaticAssert 来演示仅编译时的用法):

// asize_test.cpp
#include <boost/static_assert.hpp>
#include "asize.hpp"

#define OLD_ASIZE( a ) ( sizeof( a ) / sizeof( *a ) )

typedef char C;
typedef struct { int i; double d; } S;
typedef C A[42];
typedef S B[42];
typedef C * PA;
typedef S * PB;

int main() {
    A a; B b; PA pa; PB pb;
    BOOST_STATIC_ASSERT( ASIZET( A ) == 42 );
    BOOST_STATIC_ASSERT( ASIZET( B ) == 42 );
    BOOST_STATIC_ASSERT( ASIZET( A ) == OLD_ASIZE( a ) );
    BOOST_STATIC_ASSERT( ASIZET( B ) == OLD_ASIZE( b ) );
    BOOST_STATIC_ASSERT( ASIZE( a ) == OLD_ASIZE( a ) );
    BOOST_STATIC_ASSERT( ASIZE( b ) == OLD_ASIZE( b ) );
    BOOST_STATIC_ASSERT( OLD_ASIZE( pa ) != 42 ); // logic error: pointer accepted
    BOOST_STATIC_ASSERT( OLD_ASIZE( pb ) != 42 ); // logic error: pointer accepted
 // BOOST_STATIC_ASSERT( ASIZE( pa ) != 42 ); // compile error: pointer rejected
 // BOOST_STATIC_ASSERT( ASIZE( pb ) != 42 ); // compile error: pointer rejected
    return 0;
}

此解决方案在编译时拒绝非数组类型,因此它不会像宏版本那样被指针混淆。

KTC's solution is clean but it can't be used at compile-time and it is dependent on compiler optimization to prevent code-bloat and function call overhead.

One can calculate array size with a compile-time-only metafunction with zero runtime cost. BCS was on the right track but that solution is incorrect.

Here's my solution:

// asize.hpp
template < typename T >
struct asize; // no implementation for all types...

template < typename T, size_t N >
struct asize< T[N] > { // ...except arrays
    static const size_t val = N;
};

template< size_t N  >
struct count_type { char val[N]; };

template< typename T, size_t N >
count_type< N > count( const T (&)[N] ) {}

#define ASIZE( a ) ( sizeof( count( a ).val ) ) 
#define ASIZET( A ) ( asize< A >::val ) 

with test code (using Boost.StaticAssert to demonstrate compile-time-only usage):

// asize_test.cpp
#include <boost/static_assert.hpp>
#include "asize.hpp"

#define OLD_ASIZE( a ) ( sizeof( a ) / sizeof( *a ) )

typedef char C;
typedef struct { int i; double d; } S;
typedef C A[42];
typedef S B[42];
typedef C * PA;
typedef S * PB;

int main() {
    A a; B b; PA pa; PB pb;
    BOOST_STATIC_ASSERT( ASIZET( A ) == 42 );
    BOOST_STATIC_ASSERT( ASIZET( B ) == 42 );
    BOOST_STATIC_ASSERT( ASIZET( A ) == OLD_ASIZE( a ) );
    BOOST_STATIC_ASSERT( ASIZET( B ) == OLD_ASIZE( b ) );
    BOOST_STATIC_ASSERT( ASIZE( a ) == OLD_ASIZE( a ) );
    BOOST_STATIC_ASSERT( ASIZE( b ) == OLD_ASIZE( b ) );
    BOOST_STATIC_ASSERT( OLD_ASIZE( pa ) != 42 ); // logic error: pointer accepted
    BOOST_STATIC_ASSERT( OLD_ASIZE( pb ) != 42 ); // logic error: pointer accepted
 // BOOST_STATIC_ASSERT( ASIZE( pa ) != 42 ); // compile error: pointer rejected
 // BOOST_STATIC_ASSERT( ASIZE( pb ) != 42 ); // compile error: pointer rejected
    return 0;
}

This solution rejects non-array types at compile time so it will not get confused by pointers as the macro version does.

梦途 2024-07-12 03:14:52

到目前为止,还没有人提出一种可移植的方法来获取数组的大小,当您只有数组的实例而不是其类型时。 ( typeof 和 _countof 不可移植,因此无法使用。)

我会按以下方式执行此操作:

template<int n>
struct char_array_wrapper{
    char result[n];
};

template<typename T, int s>
char_array_wrapper<s> the_type_of_the_variable_is_not_an_array(const T (&array)[s]){
}


#define ARRAYSIZE_OF_VAR(v) sizeof(the_type_of_the_variable_is_not_an_array(v).result)

#include <iostream>
using namespace std;

int main(){
    int foo[42];
    int*bar;
    cout<<ARRAYSIZE_OF_VAR(foo)<<endl;
    // cout<<ARRAYSIZE_OF_VAR(bar)<<endl;  fails
}
  • 仅当值存在时它才有效。
  • 它是可移植的并且仅使用 std-C++。
  • 它失败并显示一条描述性错误消息。
  • 它不评估价值。 (我想不出这会成为问题的情况,因为函数无法返回数组类型,但安全总比抱歉好。)
  • 它返回大小作为编译时常量。

我将构造包装到宏中以获得一些不错的语法。 如果您想摆脱它,唯一的选择就是手动进行替换。

None has so far proposed a portable way to get the size of an array when you only have an instance of an array and not its type. (typeof and _countof is not portable so can't be used.)

I'd do it the following way:

template<int n>
struct char_array_wrapper{
    char result[n];
};

template<typename T, int s>
char_array_wrapper<s> the_type_of_the_variable_is_not_an_array(const T (&array)[s]){
}


#define ARRAYSIZE_OF_VAR(v) sizeof(the_type_of_the_variable_is_not_an_array(v).result)

#include <iostream>
using namespace std;

int main(){
    int foo[42];
    int*bar;
    cout<<ARRAYSIZE_OF_VAR(foo)<<endl;
    // cout<<ARRAYSIZE_OF_VAR(bar)<<endl;  fails
}
  • It works when only the value is around.
  • It is portable and only uses std-C++.
  • It fails with a descriptiv error message.
  • It does not evaluate the value. (I can't think up of a situation where this would be a problem because array type can't be returned by a function, but better be safe than sorry.)
  • It returns the size as compiletime constant.

I wrapped the construct into a macro to have some decent syntax. If you want to get rid of it your only option is to do the substitution manually.

所谓喜欢 2024-07-12 03:14:52

如前所述,代码实际上计算的是数组中的元素数量,而不是结构体中的元素数量。 当我需要时,我会明确地写出 sizeof() 除法​​。 如果我要把它变成一个函数,我想在它的定义中清楚地表明它需要一个数组。

template<typename T,int SIZE>
inline size_t array_size(const T (&array)[SIZE])
{
    return SIZE;
}

上面的内容与 xtofl 的类似,只是它保护反对传递一个指向它的指针(即指向一个动态分配的数组)并错误地得到错误的答案。

编辑:按照JohnMcG进行简化。
编辑:内联。

不幸的是,上面没有提供编译时答案(即使编译器在后台将其内联并优化为常量),因此不能用作编译时常量表达式。 即它不能用作声明静态数组的大小。 在 C++0x 下,如果将关键字 inline 替换为 constexpr(constexpr 是隐式内联的),这个问题就会消失。

constexpr size_t array_size(const T (&array)[SIZE])

jwfearn 的解决方案适用于编译时,但涉及typedef 有效地“保存”了新名称声明中的数组大小。 然后通过使用该新名称初始化常量来计算数组大小。 在这种情况下,我们也可以从一开始就将数组大小简单地保存为一个常量。

Martin York 发布的解决方案也可以在编译时运行,但涉及使用非标准 typeof() 运算符。 解决这个问题的方法是等待 C++0x 并使用 decltype(此时实际上不需要它来解决这个问题,因为我们将拥有 constexpr) )。 另一种替代方法是使用 Boost.Typeof,在这种情况下,我们最终会使用

#include <boost/typeof/typeof.hpp>

template<typename T>
struct ArraySize
{
    private:    static T x;
    public:     enum { size = sizeof(T)/sizeof(*x)};
};
template<typename T>
struct ArraySize<T*> {};

and 来编写

ArraySize<BOOST_TYPEOF(foo)>::size

其中 foo 是数组的名称。

As been stated, the code actually work out the number of elements in an array, not struct. I would just write out the sizeof() division explicitly when I want it. If I were to make it a function, I would want to make it clear in its definition that it's expecting an array.

template<typename T,int SIZE>
inline size_t array_size(const T (&array)[SIZE])
{
    return SIZE;
}

The above is similar to xtofl's, except it guards against passing a pointer to it (that says point to a dynamically allocated array) and getting the wrong answer by mistake.

EDIT: Simplified as per JohnMcG.
EDIT: inline.

Unfortunately, the above does not provide a compile time answer (even if the compiler does inline & optimize it to be a constant under the hood), so cannot be used as a compile time constant expression. i.e. It cannot be used as size to declare a static array. Under C++0x, this problem go away if one replaces the keyword inline by constexpr (constexpr is inline implicitly).

constexpr size_t array_size(const T (&array)[SIZE])

jwfearn's solution work for compile time, but involve having a typedef which effectively "saved" the array size in the declaration of a new name. The array size is then worked out by initialising a constant via that new name. In such case, one may as well simply save the array size into a constant from the start.

Martin York's posted solution also work under compile time, but involve using the non-standard typeof() operator. The work around to that is either wait for C++0x and use decltype (by which time one wouldn't actually need it for this problem as we'll have constexpr). Another alternative is to use Boost.Typeof, in which case we'll end up with

#include <boost/typeof/typeof.hpp>

template<typename T>
struct ArraySize
{
    private:    static T x;
    public:     enum { size = sizeof(T)/sizeof(*x)};
};
template<typename T>
struct ArraySize<T*> {};

and is used by writing

ArraySize<BOOST_TYPEOF(foo)>::size

where foo is the name of an array.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文