简体   繁体   中英

Template specialization with compile time constant

I am trying to build a specialization for a template class with a compile time constant.

The template class looks like this:

template<class TNativeItem, class TComItem = void,
         VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
class InOutComArray
{
private:
    CComSafeArray<TComItem, _vartype> _safeArray;
    // ...
public:
    InOutComArray(
        TNativeItem* items, size_t length,
        std::function<TComItem(const TNativeItem&)> convertToCom,
        std::function<TNativeItem(const TComItem&)> convertFromCom)
        : _safeArray(length)
    {
        // ...
    }

    // ...
};

Usage would be for example:

InOutComArray<BOOL, VARIANT_BOOL, VT_BOOL>(
    items, length, BOOLToVARIANT_BOOL, VARIANT_BOOLToBOOL));

However, there also exist types that don't require conversion and I wanted to provide a short hand version for this:

InOutComArray<LONG>(items, length);

I tried to implement it like this:

template<class TItem, VARTYPE _vartype = _ATL_AutomationType<TItem>::type>
class InOutComArray<TItem, void, _vartype>
    : public InOutComArray<TItem, TItem, _vartype>
{
public:
    InOutComArray(TItem* items, size_t length)
        : InOutComArray<TItem, TItem, _vartype>(
              items, length, NoConverter<TItem>, NoConverter<TItem>)
    {

    }
};

However, I get the following error:

'_vartype' : default template arguments not allowed on a partial specialization

Is there any way around that?

You first define the default arguments to be void and _ATL_AutomationType<TComItem>::type , so when exactly one argument X is given, you want InOutComArray<X> to be an InOutComArray<X, void, _ATL_AutomationType<void>::type> .

Your partial specialization contradicts this: InOutComArray<X> shall be a InOutComArray<X, X, _ATL_AutomationType<X>::type> .

Depending on what you thik will be more likely second argument, (ie void or the same as the first argument), you could make the second argument defaulted to the first one in the first place:

template<class TNativeItem, class TComItem = TNativeItem,
     VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>

That way the behavior of the partial specialization is covered, except for the additional constructor. This can be achieved by using default arguments for the constructor:

template<class TNativeItem, class TComItem = TNativeItem,
     VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
class InOutComArray
{
public:
InOutComArray(
    TNativeItem* items, size_t length,
    std::function<TComItem(const TNativeItem&)> convertToCom = NoConverter<TNativeItem>(),
    std::function<TNativeItem(const TComItem&)> convertFromCom = NoConverter<TNativeItem>());
};

According to the standard §14.5.5/8 Class template partial specializations [temp.class.spec]:

The template parameter list of a specialization shall not contain default template argument values.

Thus, the compiler rightfully complains because in your partial specialization you give default template argument value for VARTYPE _vartype = _ATL_AutomationType<TItem>::type .

Is there any way around that?

Yes, remove the default template argument from the partial specialization. You don't need it.

Per the primary template:

template<class TNativeItem, class TComItem = void,
         VARTYPE _vartype = _ATL_AutomationType<TComItem>::type>
class InOutComArray

These types are equivalent:

InOutComArray<LONG>
InOutComArray<LONG, void, _ATL_AutomationType<TComItem>::type>

And whenever InOutComArray is instantiated with TComItem = void , you will get the partial specialization:

template<class TItem, VARTYPE _vartype>
class InOutComArray<TItem, void, _vartype>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM