July 12, 2001 tools

STL Enumerator Iterator

Have you ever been jealous of the VB programmer who could write this:

sub EnumVariants(col as Collection)
    dim v as variant for each v in col
        ' Do something with v
    next v
end sub

when we poor C++ programmers have to write this:

void EnumVariants(IEnumVARIANT* pevar)
{
    HRESULT hr;
    enum { CHUNKSIZE = 100 };
    VARIANT rgvar[CHUNKSIZE] = { 0 };
    do {
        ULONG cFetched;

        hr = pevar->Next(CHUNKSIZE, rgvar, &cFetched)
        if( SUCCEEDED(hr) ) {
            if( hr == S_OK ) cFetched = CHUNKSIZE;
            for( ULONG i = 0; i < cFetched; i++ )
            {
                // Do something with rgvar[i]
                VariantClear(&rgvar[i]);
            }
        }
    }
    while (hr == S_OK);
}

Well no more! I’ve built an enumeration iterator class that holds IEnumXxx and exposes an STL-compatible iterator:

template <typename EnumItf, const IID* pIIDEnumItf,
          typename EnumType, typename CopyClass = _Copy<EnumType> >
class enum_iterator;

It uses the same copy policy classes as ATL for convenience. Now you can write:

void EnumVariants(IEnumVARIANT* pevar)
{
    typedef enum_iterator<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT> EVI;
    for( EVI i = EVI(pevar); i != EVI(); ++i )
    {
        VARIANT&    v = *i;
        // Do something with v
    }
}

or you can use the typedefs for the standard enumerators:

void EnumVariants(IEnumVARIANT* pevar)
{
    for( variant_iterator i = variant_iterator(pevar);
         i != variant_iterator();
         ++i )
    {
        VARIANT&    v = *i;
        // Do something with v
    }
}

or you can use STL algorithms (this is my personal favorite):

struct DoSomethingWithVariant
{
    void operator()(const VARIANT& v)
    {
        // Do something with v
    }
};

void EnumVariants(IEnumVARIANT* pevar)
{
    for_each(enum_variant(pevar),
             enum_variant(),
             DoSomethingWithVariant());    
}

Feel free to download the enum_iterator class for your own use. You’ll also need a supporting file, atlcopies.h.