简体   繁体   中英

class template specialization with template

I have a class template name to detect type names. It works for simple types such as int , float . However, for some template type like std:pair , the compiler (VS2013) reports error at the line when I try to define its static member variable.

#include <cassert>
#include <memory>

using namespace std;

template<class T> struct name{ static const char* value; };

template<class T> const char* name<T>::value = "unknown";
template<> const char* name<int>::value = "int";
template<> const char* name<float>::value = "float";
template<class T1, class T2> const char* name<pair<T1, T2> >::value = "pair"; //compilation error

void main()
{
    assert(name<int>::value == "int");
    assert(name<float>::value == "float");
    assert(name<double>::value == "unknown");
    assert((name<pair<int, char> >::value) == "pair");
}

If I replace that line with the following four lines, the program works as expected.

template<class T1, class T2> struct name < pair<T1, T2> > {
    static const char* value;
};
template<class T1, class T2> const char* name<pair<T1, T2> >::value = "pair";

But this way looks ugly due to some duplicate code. Is there any way to walk around?

Updated to have fixed some apparent standard compliant issues.

First of all: Any explicit specialization has to be introduced by template<> . Try to stay standard-compliant.

But this way looks ugly due to some duplicate code. Is there any way to walk around?

No. The parameter and argument list in a member definition that is not an explicit specialization must match the lists of the primary template or one of its partial specializations, and it corresponds to the member of the template whose lists it matches. [temp.class.spec.mfunc]:

The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization. The template argument list of a member of a class template partial specialization shall match the template argument list of the class template partial specialization.

So you have to partially specialize the template. You could use a macro for that though:

#define REM_PAR(...) __VA_ARGS__
#define PART_SPEC(string, params, ...) \
    template<REM_PAR params> struct name <__VA_ARGS__ > \
    {  static const char* value; }; \
    \
    template<REM_PAR params> const char* name<__VA_ARGS__>::value = string;

PART_SPEC("pair", (class T, class U), pair<T,U>)

First of all, for reference, this is how your pseudo code looks in C++:

#include <cassert>  // for assert
#include <cstring>  // for std::strcmp
#include <utility>  // for std::pair

template <class T> struct name
{ static const char * const value; };

template <class T>
const char * const name<T>::value = "unknown";

template <>         // "template <>" for specialization
const char * const name<int>::value = "int";

template <>         // "template <>" for specialization
const char * const name<float>::value = "float";

// template <class T1, class T2>                               // Error here (partial
// const char * const name<std::pair<T1, T2>>::value = "pair"; // spec'n not allowed)

int main()  // return type int
{
    assert(std::strcmp(name<int>::value, "int") == 0);      // strcmp!
    assert(std::strcmp(name<float>::value,"float") == 0);
    assert(std::strcmp(name<double>::value, "unknown") == 0);
    assert(std::strcmp(name<std::pair<int, char>>::value,"pair") == 0);
}

Now, here's a way you can make partial specialization work: Specialize the entire template.

template <class T1, class T2> struct name<std::pair<T1, T2>>
{ static const char * const value; };

template <class T1, class T2>
const char * const name<std::pair<T1, T2>>::value = "pair";

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