How should I do this explicit specialization?
-
28-09-2019 - |
문제
Is following design possible?:
template <typename T>
class Test{
public:
template <typename Z>
void doSomething();
//rest of things
private:
T obj;
//some things
};
Now if it was possible I'd do some explicit specializations for doSomething so that at the end I'd have some versions like below:
void doSomething<int>(){
//do something
}
void doSomething<double>(){
//do something
}
...etc
which seems impossible I can't find any syntax to do the job then I thought maybe the design should be as it follows so that all template arguments should be passed to template class itself:
template <typename T,typename Z>
class Test{
public:
void doSomething();
//rest of things
private:
T obj;
//some things
};
Then I tried partial specialization which didn't even compile:
template <typename T>
void Test<T,int>::doSomething(){
//do something
}
template <typename T>
void Test<T,double>::doSomething(){
//do something
}
...etc
I got the following errors for explicit specialization:
error#1:template argument list following class template name must list parameters in the order used in template parameter list.
error#2:'Container1' :too few template arguments.
해결책
In order to explicitly specialize doSomething
you have to also explicitly specialize Test
.
From 14.7.3/18 :
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
다른 팁
You cannot explicitly specialize a member template unless its enclosing class templates are also explicitly specialized.
So only something like this will work:
template<> template<>
void Test<int>::doSomething<int>()
{
}
you can always make the function inline
template <class T>
class Test
{
public:
template <class Z>
void doSomething() { cout << "default" << endl; }
template<>
void doSomething<int>() { cout << "int" << endl;}
template<>
void doSomething<double>() { cout << "double" << endl; }
private:
T obj;
};
I think this one is picky. I suppose you can't do it, read this.
Not sure if this is a bug in g++ but this compiles and produce what I expect.
#include<typeinfo>
#include<iostream>
template<typename T>
class Test
{
public:
template<typename Z>
void doSomething();
private:
T obj;
};
template<typename T>
template<typename Z>
void Test<T>::doSomething()
{
Z val;
std::cout << __func__ << ": type " << typeid(val).name() << std::endl;
}
int main(int argc, char *argv[])
{
Test<double> a;
a.doSomething<int>();
a.doSomething<double>();
}
icecrime posted a temporary answer and it gets compiled due to some bug probably by visual C++ 2008:
template <typename T>
class Test{
public:
template <typename Z>
void doSomething();
//rest of things
private:
T obj;
//some things
};
template <>
template <typename T>
void Test<T>::doSomething<int>(){
//do something
}
Check his current answer though. The funny thing at least with VC++ 2008 is, no problem compiling when specializing with inline definitions, but for specializations with not-inline definitions once there's more than one version it doesn't get compiled successfully.