简体   繁体   中英

Template class partial specialization syntax

The following basic example of partial template class specialization, taken from this wiki page :

template <typename Key, typename Value>
class KeyValuePair { /* something generic */ };

template <typename Key>
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ };

KeyValuePair<int> kvpi;

generates a compiler error:

prog.cpp:10:17: error: wrong number of template arguments (1, should be 2)  KeyValuePair<int> kvpi;

Why? what am I doing wrong? How a partial template class specialization should be declared and instantiated?

I am expecting variable kvpi to be a partially specialized template class instance of type KeyValuePair<int,bool> .

You appear to be confusing partial specialization with default template arguments. It further appears you need both (for reasons unstated, but not really important). Though not entirely intuitive, it can be accomplished as follows:

#include <iostream>

template <typename Key, typename Value = bool>
class KeyValuePair
{
public:
    KeyValuePair()
    {
        std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
    }
};

template <typename Key>
class KeyValuePair<Key, bool>
{
public:
    KeyValuePair()
    {
        std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
    }
};


int main()
{
    KeyValuePair<int,int> kvp1;
    KeyValuePair<int> kvp2;
}

Output

KeyValuePair<int, int>::KeyValuePair() [Key = int, Value = int]:original
KeyValuePair<int, bool>::KeyValuePair() [Key = int, Value = bool]:specialized

The confusing part to some is the default argument specification, but a template that follows which will never actually see fruition with that default-arg because of the later specialization. In such cases I prefer to forward-declare the template with its default argument list. At least for me it makes it slightly easier to read. You may (or not) choose to do the same if you feel it offers clarity. Something like:

template <typename Key, typename Value = bool>
class KeyValuePair;

template <typename Key, typename Value>
class KeyValuePair
{
public:
    KeyValuePair()
    {
        std::cout << __PRETTY_FUNCTION__ << ':' << "original\n";
    }
};

template <typename Key>
class KeyValuePair<Key, bool>
{
public:
    KeyValuePair()
    {
        std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n";
    }
};

Partial template specialization doesn't allow you to forget a template parameter. You have to write:

KeyValuePair<int, bool> kvpib;

and correct specialization will be used.

But you can use inheritance to achieve what you want:

template <typename Key>
class KeyBoolPair : public KeyValuePair<Key, bool> {};

KeyBoolPair<int> kbpi;

or if you use C++11 or greater:

template <typename Key>
using KeyBoolPairBis = KeyValuePair<Key, bool>;

KeyBoolPairBis<int> kbpbi;

example: http://coliru.stacked-crooked.com/a/5095fc5c358d291a

You define your partial specialization correctly, but the template expect 2 argument and you provide only one.

You may use default argument:

template <typename Key, typename Value = bool>
class KeyValuePair {};

to allow

KeyValuePair<int> kvpi;

And you may keep your partial specialization if needed

template <typename Key>
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ };

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