Implementing an STL-Based Collection
Copy policy classes are utility classes used to initialize, copy, and delete data. Copy policy classes allow you to define copy semantics for any type of data, and to define conversions between different data types.
ATL uses copy policy classes in its implementations of the following templates:
By encapsulating the information needed to copy or convert data in a copy policy class that can be passed as a template argument, the ATL developers have provided for extreme reusability of these classes. For example, if you need to implement a collection using any arbitrary data type, all you need to provide is the appropriate copy policy; you never have to touch the code that implements the collection.
Any class that provides the following static functions is a copy policy class:
static void init(DestinationType* p);
static HRESULT copy(DestinationType* pTo, const SourceType* pFrom);
static void destroy(DestinationType* p);
The types DestinationType and SourceType can be replaced with arbitrary data types for each copy policy.
init is used to initialize data, copy to copy data, and destroy to free the data. The precise meaning of initialization, copying, and destruction are the domain of the copy policy class and will vary depending on the data types involved.
There are two guarantees on the use of a copy policy class:
The only requirement on the implementation of a copy policy class is that it behaves correctly given these guarantees.
Note Although copy policy classes can be defined for any arbitrary data types, their use within ATL code will limit the types that make sense. For example, when using a copy policy class with ATL's collection or enumerator implementations, DestinationType must be a type that can be used as a parameter in a COM interface method.
ATL provides two copy policy classes in the form of the _Copy and _CopyInterface template classes:
Typically, you'll need to define your own copy policy classes for heterogeneous copying (that is, conversion between data types). For some examples of custom copy policy classes, look at the files VCUE_Copy.h and VCUE_CopyString.h in the ATLCollections project. These files contain two template copy policy classes, GenericCopy
and MapCopy
, plus a number of specializations of GenericCopy
for different data types.
GenericCopy
allows you to specify the SourceType and DestinationType as template arguments. Here's the most general form of the GenericCopy
class from VCUE_Copy.h:
template <class DestinationType, class SourceType = DestinationType>
class GenericCopy
{
public :
typedef DestinationType destination_type;
typedef SourceType source_type;
static void init(destination_type* p)
{
_Copy<destination_type>::init(p);
}
static void destroy(destination_type* p)
{
_Copy<destination_type>::destroy(p);
}
static HRESULT copy(destination_type* pTo, const source_type* pFrom)
{
return _Copy<destination_type>::copy(pTo, const_cast<source_type*>(pFrom));
}
}; // class GenericCopy
VCUE_Copy.h also contains the following specializations of this class: GenericCopy<BSTR>
, GenericCopy<VARIANT, BSTR>
, GenericCopy<BSTR, VARIANT>
. VCUE_CopyString.h contains specializations for copying from std::strings: GenericCopy<std::string>
, GenericCopy<VARIANT, std::string>
, and GenericCopy<BSTR, std::string>
. You could enhance GenericCopy
by providing further specializations of your own.
MapCopy
assumes that the data being copied will be stored in an STL-style map, so it allows you to specify the type of map in which the data is stored and the destination type. The implementation of the class just uses the typedefs supplied by the MapType class to determine the type of the source data and to call the appropriate GenericCopy
class. No specializations of this class are needed.
template <class MapType, class DestinationType = MapType::referent_type>
class MapCopy
{
public :
typedef DestinationType destination_type;
typedef MapType::value_type source_type;
typedef MapType map_type;
typedef MapType::referent_type pseudosource_type;
static void init(destination_type* p)
{
GenericCopy<destination_type, pseudosource_type>::init(p);
}
static void destroy(destination_type* p)
{
GenericCopy<destination_type, pseudosource_type>::destroy(p);
}
static HRESULT copy(destination_type* pTo, const source_type* pFrom)
{
return GenericCopy<destination_type, pseudosource_type>::copy(pTo, &(pFrom->second));
}
}; // class MapCopy