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

Detailed Description

Outline

Purpose

Provide an value-semantic type to represent type_info objects.

Classes

Canonical header: bsl_typeindex.h

See also
bsl_typeinfo

Description

This component defines an in-core value-semantic class, bsl::type_index, capable of representing a handle to a std::type_info object that supports all the operations needed to serve as a key type in an associative or unordered container.

This implementation of type_index satisfies the contracts for the native std::type_index specified in the ISO standard, including a specialization for the native standard library std::hash. It further provides an overload for hashAppend to support the BDE hashing framework, and therefor idiomatic usage with bsl::hash. In general, the recommended best practice is that users of bsl containers should use the bsl::type_index class, while users of std containers should use the std::type_index class.

Usage

This section illustrates intended use of this component.

Example 1: Basic Use of bsl::type_index

Assume you are implementing a graphics library, and need to represent a variety of shapes. You might have a simple hierarchy, such as:

+-----------------------------------------------------------------+
| |
| .---------. |
| ( Shape ) |
| `---------' |
| ^ ^ ^ |
| / | \ |
| / | \ |
| / | \ |
| ,------. ,--------. ,-------. |
| ( Circle ) ( Triangle ) ( Polygon ) |
| `------' `--------' `-------' |
| |
+-----------------------------------------------------------------+

In order to manage the creation of objects in our hierarchy, we might deploy the Abstract Factory pattern: https://en.wikipedia.org/wiki/Abstract_factory_pattern using objects of type bsl::function<shared_ptr<Shape> > as factories.

First, we define our basic class hierarchy.

class Shape {
public:
virtual ~Shape() = 0;
// Destroy this object.
// Further details elided from example.
};

Then, we create a utility class containing a registry of factory functions indexed by their corresponding std::type_info, using bsl::type_index to provide the value-semantic wrapper needed for the key used in the container. This registry will enable us to abstract away different constructors of the concrete object types.

struct ShapeUtil {
// This 'struct' provides a namespace for utilities to manage the
// creation of objects implementing the 'Shape' protocol.
// PUBLIC TYPES
typedef bsl::function<bsl::shared_ptr<Shape>(int, int)> CreateFunction;
AbstractFactory;
// CLASS METHODS
template <class SHAPE_TYPE>
static bsl::shared_ptr<Shape> make(int x, int y);
// Return a 'shared_ptr' owning a newly created object of (template
// parameter) 'SHAPE_TYPE' at the specified position '(x, y)' if
// 'SHAPE_TYPE' has been registered with this utility, and an empty
// 'shared_ptr' otherwise.
template <class SHAPE_TYPE, class FACTORY>
static bool registerFactory(FACTORY factory);
// Register the specified 'factory' creating objects of (template
// parameter) 'SHAPE_TYPE'; return 'true' if this is the first
// successful attempt to register such a factory function, and
// 'false' otherwise.
private:
static AbstractFactory s_registry; // registry for factories
};
Forward declaration.
Definition bslstl_function.h:934
Definition bslstl_sharedptr.h:1830
Definition bslstl_unorderedmap.h:1089

Now, we can implement the register and make functions, using the standard typeid operator to create the key values as needed.

template <class SHAPE_TYPE>
bsl::shared_ptr<Shape> ShapeUtil::make(int x, int y) {
AbstractFactory::iterator it = s_registry.find(typeid(SHAPE_TYPE));
if (s_registry.end() == it) {
return 0; // RETURN
}
return it->second(x, y);
}
template <class SHAPE_TYPE, class FACTORY>
bool ShapeUtil::registerFactory(FACTORY factory) {
return s_registry.emplace(typeid(SHAPE_TYPE), factory).second;
}

Next, we provide several concrete implementations of our Shape class, to demonstrate use of this hierarchy.

class Circle : public Shape {
// This class represents a circle, described by a position and radius.
public:
// CREATORS
Circle(int x, int y, int radius);
// Create a 'Triangle' having the it center at the specified
// position '(x, y)', and having the specified 'radius'.
~Circle();
// Destroy this object.
// Further details elided from example.
};
class Triangle : public Shape {
// This class represents a triangle.
public:
// CREATORS
Triangle(int x1, int y1, int x2, int y2, int x3, int y3);
// Create a 'Triangle' having the specified vertices, '(x1, y1)',
// '(x2, y2)', and '(x3, y3)'.
~Triangle();
// Destroy this object.
// Further details elided from example.
};
class Polygon : public Shape {
// This class represents a polygon having an arbitrary number of
// vertices.
public:
// CREATORS
template <class ITERATOR>
Polygon(ITERATOR firstPoint, ITERATOR endPoint);
// Create a Polygon having vertices given by the specified range
// '[firstPoint, endPoint)'.
~Polygon();
// Destroy this object.
// Further details elided from example.
};

Then, we provide some simple factory functions to create some shapes at the specified coordinates.

bsl::shared_ptr<Shape> makeCircle(int x, int y)
// Return a 'Circle' at the specified position '(x, y)'.
{
return bsl::make_shared<Circle>(x, y, 5);
}
bsl::shared_ptr<Shape> makeTriangle(int x, int y)
// Return a 'Triangle' with its lower left vertex at the specified
// position '(x, y)'.
{
return bsl::make_shared<Triangle>(x, y, x+3, y+4, x+6, y);
}

Finally, we can exercise the whole system in a simple test driver. Note that as we do not register a factory function for the Polygon class, the attempt to create a Polygon will fail.

int main()
// Simulated test driver.
{
// Install a test allocator to confirm there are no memory leaks.
bslma::TestAllocator ta("Usage example default allocator");
bool registeredCircle = ShapeUtil::registerFactory<Circle>(makeCircle);
assert(registeredCircle);
bool registeredTriangle =
ShapeUtil::registerFactory<Triangle>(makeTriangle);
assert(registeredTriangle);
bsl::shared_ptr<Shape> example = ShapeUtil::make<Circle>(10, 10);
assert(0 != bsl::dynamic_pointer_cast<Circle>(example));
example = ShapeUtil::make<Triangle>(10, 10);
assert(0 != bsl::dynamic_pointer_cast<Triangle>(example));
example = ShapeUtil::make<Polygon>(10, 10);
assert(0 == example);
return 0;
}
Definition bslma_defaultallocatorguard.h:186
Definition bslma_testallocator.h:384