How to Tell If a Class/Struct Has No Data Members

Is there an easy way to tell if a class/struct has no data members?

Since C++11, you can use the std::is_empty trait.

If you are on paleo-compiler diet, there is a trick: you can derive a new helper class from the class in question and check whether sizeof(helper) == some_known_size. This relies on empty base optimisation, which is performed by all mainstream C++ Compilers, and ensures that an empty base class will take up zero space in a derived class.

Boost does this in its is_empty type trait implementation.

The general outline is as follows:

template <typename T>
struct is_empty {
struct helper : T { int x; };
static bool const VALUE = sizeof(helper) == sizeof(int);
};

The actual Boost implementation is more complex since it needs to account for virtual functions (all mainstream C++ compilers implement classes with virtual functions by adding an invisible data member for the virtual function table to the class).

Check if a struct is empty

It sounds like what you want is to find out if this struct has any non-zero values. As you can see in the comments, there are a couple exceptions you may want to consider, but for the simple solution we can copy this previous answer.

// Checks if all bytes in a teststruct are zero
bool is_empty(teststruct *data) {
unsigned char *mm = (unsigned char*) data;
return (*mm == 0) && memcmp(mm, mm + 1, sizeof(teststruct) - 1) == 0;
}

How to check if a struct is NULL in C or C++

You need some way to mark AnotherStruct stData empty.

  • First check (or double-check) the documentation and comments related to AnotherStruct, possibly ask those who made it if they are available, to find out if there is an official way to do what you want.

  • Perhaps that struct has a pointer, and if it is null pointer, the struct is empty. Or perhaps there is an integer field where 0 or -1 or something can mean empty. Or even a boolean field to mark it empty.

  • If there aren't any of the above, perhaps you can add such a field, or such an interpretation of some field.

  • If above fails, add a boolean field to MyData to tell if stData is empty.

  • You can also interpret some values (like, empty string? Full of 0xFF byte?) of data1 and/or data2 meaning empty stData.

  • If you can't modify or reinterpret contents of either struct, then you could put empty and non-empty items in different containers (array, list, whatever you have). If MyData items are allocated from heap one-by-one, then this is essentially same as having a free list.

  • Variation of above, if you have empty and non-empty items all mixed up in one container, then you could have another container with pointers or indexes to the the non-empty items (or to the empty items, or whatever fits your need). This has the extra complication, that you need to keep two containers in sync, which may or may not be trivial.

I know struct is a class but the code says No

At first, you are right. a struct is just a class under the hood.

Some indications:

1- You can forward declare one of them and then define it with the other one (although some compliers may issue a warning).

class A;     // declaration of A with class
struct A { /* definition of A with struct */ } ;

2- is_class<> returns true for both.

3- There is no is_struct<> in <type_traits>.

4- In most cases, the two keywords are interchangeable. (e.g: in scoped enum).

However, they have important syntactic differences:

struct

  • Grants public access to its members by default.
  • Backward compatible with C if used without C++ features.

class

  • Grants private access to its members by default.
  • Not compatible with C.

Which one to use is a matter of convention and/or convenience.

Generally, I prefer using struct as an aggregate of data (record). And class for other uses.

Now we come to your second question:

Why does the code show two different things?

It does not.

Because is_class<> is not about types but rather it is about type categories. (i.e. is_class<x> checks if the type x is a class or not) whereas is_same<> is about types themselves ((i.e. is_same<x, y> checks if type x is as same as type y or not))

If you change struct in your test code into class, is_same<> would still outputs “No” because A is a type and B is another type even if they both have the same type category which is class.

Based on your code:

A a;  // a is of type A
B b; // b is of type B
// Can we say that a and b of the same type?
// No. And this is what is_same<> checks.

Inquire members of a struct or class

No. The language feature that you describe is called reflection. C++ has no support for reflection.

It is of course possible to maintain the information about classes and members and such in an external structure. Using a preprocessor, it is possible to build a system that allows defining a class and its reflection metadata without repetition.


There are proposals to add (static) reflection to the language: N4428, 4447, N4451, SG 7 Hopefully reflection will become part of C++ in the future.

How to check for an empty struct?

You can use == to compare with a zero value composite literal because all fields in Session are comparable:

if (Session{}) == session  {
fmt.Println("is zero value")
}

playground example

Because of a parsing ambiguity, parentheses are required around the composite literal in the if condition.

The use of == above applies to structs where all fields are comparable. If the struct contains a non-comparable field (slice, map or function), then the fields must be compared one by one to their zero values.

An alternative to comparing the entire value is to compare a field that must be set to a non-zero value in a valid session. For example, if the player id must be != "" in a valid session, use

if session.playerId == "" {
fmt.Println("is zero value")
}

Is there a SFINAE-template to check if a class has no functions of any kind?

No, there's no such method. Consider the following:

struct A { };
struct B { void UniqueFunctionName9814(); };

No SFINAE method can distinguish these, because you can't enumerate member function names, nor can you predict random function names. Hence B::UniqueFunctionName9814 can't be detected, and apart from B::UniqueFunctionName9814 the two classes are identical.



Related Topics



Leave a reply



Submit