BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslmf_isempty

Detailed Description

Outline

Purpose

Provide a compile-time check for detecting an empty class type.

Classes

See also
bslmf_isclass.h

Description

This component defines a meta-function, bsl::is_empty and a template variable bsl::is_empty_v, that represents the result value of the bsl::is_empty meta-function, which may be used to determine whether a type is a class or struct with no non-static data members other than bit-fields of length 0, no virtual member functions, no virtual base classes, and no base class B for which is_empty<B>::value is false. This meta-function conforms to the definition of the C++11 standard is_empty meta-function in section [meta.unary.prop].

An empty class type type is usually stateless and, can be "stored" in a zero-length memory region. (Hypothetically, an empty object can hold state by means a global address-to-state map, but such a design is rare and is discouraged.) When a class inherits from an empty type, the compiler is expected to optimize away the storage requirements of the empty base class. This optimization is known as the "Empty Base Optimization" or "EBO".

Note that the template variable is_empty_v is defined in the C++17 standard as an inline variable. If the current compiler supports the inline variable C++17 compiler feature, bsl::is_empty_v is defined as an inline constexpr bool variable. Otherwise, if the compiler supports the variable templates C++14 compiler feature, bsl::is_empty_v is defined as a non-inline constexpr bool variable. See BSLS_COMPILERFEATURES_SUPPORT_INLINE_VARIABLES and BSLS_COMPILERFEATURES_SUPPORT_VARIABLE_TEMPLATES macros in bsls_compilerfeatures component for details.

Usage

In this section we show intended use of this component.

Example 1: Compute Storage Requirements for a Type

Suppose we wish to create a generic function that will allocate a record comprising a value of specified t_TYPE and a description in the form of a null-terminated character string. First, we declare the function prototype:

template <class t_TYPE>
void *makeRecord(const t_TYPE& value, const char* description);

Next, we implement the function so that the copy of value takes up no space if t_TYPE is an empty class. We manage this by computing a zero storage requirement if is_empty<t_TYPE>::value is true:

#include <cstring>
#include <new>
template <class t_TYPE>
void *makeRecord(const t_TYPE& value, const char* description)
{
// 'ValueSize' is computed at compile time.
static const std::size_t ValueSize = bsl::is_empty<t_TYPE>::value ?
0 : sizeof(t_TYPE);
// Allocate memory for value and description
const std::size_t MemSize = ValueSize + std::strlen(description) + 1;
void *mem = ::operator new(MemSize);
// Construct copy of value at front of allocated memory
::new(mem) t_TYPE(value);
// Copy description into space following value.
std::strcpy(static_cast<char*>(mem) + ValueSize, description);
return mem;
}
Definition bslmf_isempty.h:315

Finally, we use makeRecord with both an empty and non-empty value type:

struct EmptyMarker { };
int main()
{
void *record1 = makeRecord(9999, "four nines");
// Value takes 'sizeof(int)' bytes at front of record.
assert(9999 == *static_cast<int*>(record1));
assert(0 == std::strcmp(static_cast<char*>(record1) + sizeof(int),
"four nines"));
void *record2 = makeRecord(EmptyMarker(), "Empty");
// Value takes no space at front of record.
assert(0 == std::strcmp(static_cast<char*>(record2), "Empty"));
::operator delete(record1);
::operator delete(record2);
return 0;
}