Infer subclass template types in a template
I have a class that derives from a templated class:
template <typename A,typename B>
class TemplatedClass {
};
class Hello : public TemplatedClass<int,float>
{
};
Now, I want to make a templated class that will infer the types int,float from Hello
.
template <template <typename A,typename B> class C>
class Check
{
void Foo(A,B,C)开发者_JAVA百科
{
// A is int .. B is float .. C is Hello
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Check<Hello> a;
}
How can i do this ?
Edit:
I want to pass the class Hello and have the template infer the types used by its subclass TemplatedClass .
So, when I create a class Check<Hello>
it will get the types int and float
I can't really change the TemplatedClass to include typedefs (it's from an an external .lib)
Edit:
I've changed the template to use Class , I get this error though:
error C3200: 'Hello' : invalid template argument for template parameter 'C', expected a class templateFirst, change that typename
to class
, §14.1 [temp.param] p1
:
type-parameter:
- class identifieropt
- class identifieropt = type-id
- typename identifieropt
- typename identifieropt = type-id
- template <template-parameter-list > class identifieropt
- template <template-parameter-list > class identifieropt = id-expression
Next, make a partial specialization:
template<class T>
class Check;
template< // not 'typename' vvvvv
template<typename,typename> class C,
typename A, typename B
>
struct Check<C<A,B> >{
// ...
};
Though, you still can't pass just Hello
to the template, because even though Hello
derives from TemplatedClass
, type conversion is not allowed for template parameters:
Check<Hello> c; // nope, 'Hello' is not a template
You could add the following typedef to the Hello
class:
class Hello
: TemplatedClass<int,float>
{
public:
typedef TemplatedClass<int,float> base_type;
};
And do:
Check c; // OK
But then the C
parameter in Check
will be template TemplatedClass
, not Hello
. Sadly, there's no way to achieve that directly. One solution is to pass the derived type either as an extra template parameter or just pass the derived type as the only parameter and do the type extraction internally:
template<class T>
class CheckInternal;
template<
template<typename,typename> class C,
typename A, typename B
>
class CheckInternal<C<A,B> >{
public:
typedef A type_A;
typedef B type_B;
};
template<class T>
class Check{
typedef typename T::base_type T_base_type;
typedef typename CheckInternal<T_base_type>::type_A type_A;
typedef typename CheckInternal<T_base_type>::type_B type_B;
void foo(type_A a, type_B b){
// ...
}
};
// usage:
C<Hello> c; // OK!
You could do something like this:
template <template <typename A,typename B> typename C>
class Check
{
template<typename A, typename B>
void Foo(A a, B b) {
// C<A,B> would reconstruct the template type
}
}
// use:
Check<Hello> a;
a.Foo(true,1.f);
or alternatively, this (it's not exactly clear what your intent is):
template <typename A,typename B>
class TemplatedClass {
typedef A TypeA;
typedef B TypeB;
};
template <typename C>
class Check
{
void Foo(typename C::TypeA& a, typename C::TypeB&) {}
}
// use:
Check<Hello<int,float> > a;
a.Foo(1,1.f);
Try something like:
template <typename A,typename B>
class TemplatedClass {
public:
typedef A firstType;
typedef B secondType;
};
class Hello : public TemplatedClass<int,float>
{
public:
typedef firstType Type1;
typedef secondType Type2;
};
template <typename C>
class Check
{
typedef typename C::Type1 A;
typedef typename C::Type2 B;
void Foo(A,B,C)
{
// A is int .. B is float .. C is Hello
}
};
I think you can do it by creating a templated class for Hello and then typedefing a specialization of it. Something like:
template <typename A, typename B>
class HelloBase : public TemplatedClass<A, B>
{
public:
typedef A Type1;
typedef B Type2;
};
typedef HelloBase<int, float> Hello;
template <typename C>
class Check
{
typedef typename C::Type1 A;
typedef typename C::Type2 B;
void Foo(A,B,C)
{
// A is int .. B is float .. C is Hello
}
};
...
Check<Hello> a;
So TemplatedClass doesn't need to change, and you can put everything you were going to put in Hello into HelloBase (using the templating as a tool for simply carrying around types).
What you want is impossible in the general case- what if Hello
derived from TemplatedClass
twice?
It is, however, fairly simple to do, even non-intrusively, under C++0x.
template<typename A, typename B> struct retval {
typedef A first;
typedef B second;
};
template<typename one, typename two> one first(const TemplatedClass<one, two>& ref);
template<typename one, typename two> two second(const TemplatedClass<one, two>& ref);
template<typename T> class Check {
typedef decltype(first(*static_cast<T*>(nullptr))) first;
typedef decltype(second(*static_cast<T*>(nullptr))) second;
};
In C++03 then you can still get the parameters inside the method, but can't access them outside, unless you insert special typedefs.
精彩评论