Consider the code below:
template <typename T>
class A{
...
}
template <class U>
class B{
...
}
int main {
B<A<int>> a;
...
}
How can I get the template parameter of A (int in this case) inside B, if A<int> is the template parameter for B?
I could parametrize B as follows, but I feel like I am sending an unnecessary piece of information.
template <class AA, typename T>
class B { ... }
The reason I do not simply use template <typename T> for class B is that I have a pointer to class A inside B, and I want to use the template parameter class AA to see if that pointer is const or not, hence have the correct type for the member pointer in B.
There are several ways, depending of that you might change:
Quick way, specialize B
template <class> class B;
template <class T>
class B<A<T>>
{
// Use directly T
//...
};
Add info in A directly (as std containers do with value_type)
template <typename T>
struct A
{
using my_type = T;
};
// Then in `B<U>`, use `typename U::my_type`
Use external traits to extract information from A (as std::iterator_traits) (that also allows to handle built-in types):
template <typename T>
struct ATrait;
template <typename T>
struct ATrait<A<T>>
{
using my_type = T;
};
// Possibly a generic one
template <template <typename> class C, typename T>
struct ATrait<C<T>>
{
using my_type = T;
};
// Then in `B<U>`, use `typename ATrait<U>::my_type`
I think the following does what you want:
#include<type_traits>
template<class>
class A{};
template<class>
struct get_inner;
template<template<class> class TT, class T>
struct get_inner<TT<T>> {
using outer = TT<T>;
using inner = T;
};
template<class TT>
struct B {
using A = TT;
using inner = typename get_inner<std::decay_t<A>>::inner;
};
int main(int argc, char *argv[])
{
static_assert(std::is_const_v<typename B<const A<int>>::A>);
static_assert(!std::is_const_v<typename B<A<int>>::A>);
}
Note the std::decay_t, it wouldn't work with the const parameter directly (hence we cannot just specialize B in this way). Maybe decay_t is a bit strong but it works^^
Try this
template <typename X> class B;
template <template <typename> class XX, typename T>
class B<XX<T>>
{
// your implementation
};
B<A<int>> a;
Let's say there is a class A and MyType
template<typename DataType>
class MyType {
...
}
template<typename MyType>
class A {
...
}
When I create an instance of A with A<MyType<int>> how can I access the template type int inside A?
Expose a type alias to the user:
template<typename DataType>
class MyType {
public:
using InnerDataType = DataType;
};
template<typename MyType>
class A {
public:
using InnerType = MyType;
};
Usage:
using MyA = A<MyType<int>>;
static_assert(std::is_same<
typename MyA::InnerType::InnerDataType,
int>{});
live example on wandbox
Another method would be like this:
template <typename DataType>
class MyType { ... };
template<typename X> // template parameter name changed for clarity
class A; // intentionally left undefined
template<typename Y>
class A<MyType<Y>> { ...Y... }; // a specialisation
... A<MyType<int>> ... // Y in the definition of A is int
This way one can only instantiate A with instances of MyType.
If there's a need to instantiate A with any templated type, one uses a bit different specialisation:
template<template<typename...> X, typename Y>
class A<X<Y>> { ...X<Y>... }; // a specialisation
... A<MyType<int>> ... // X in the definition of A is MyType, Y is int
... A<OtherType<double>> ... // X is OtherType, Y is double
This way, one can pass any templated type that doesn't have non-type template parameters.
I have a class A and a class template B declared as follows:
class A;
template <class T>
class B;
I want to declare a specialization of B for T=int, which coincides with A, i.e. something like this
template<>
class B<int> = A;
You can emulate such behavior of B via nested classes and C++11 template aliases:
class A;
template <class T>
struct B_
{
class type{ /* Implement your general version of B here */ };
};
template <>
struct B_<int>
{
using type = A;
};
template <class T>
using B = typename B_<T>::type;
Live demo
I have five classes, declared so:
template <typename T>
class A {
void fn(X);
};
template <typename T>
class B {};
class C {};
class D {};
class X {};
and I have two instances declared so:
A<B<C>> abc;
A<B<D>> abd;
How can I templatize fn so that one must call abc.fn() with an object of type C and abd.fn() with an object of type D?
You can do a partial specialization of your class like this:
template <typename T> class A;
template <typename T> class B {};
template <typename T>
class A<B<T> > {
public:
void fn(T) { }
};
class C {};
class D {};
int main(int,char**)
{
A<B<C>> abc;
A<B<D>> abd;
abc.fn(C());
abd.fn(D());
return 0;
}
If you want it to work for any template, and not just B, you can partially specialize class A like this:
template <typename T,template <typename> class U>
class A<U<T> > {
public:
void fn(T) { }
};
This is not going to be too pretty.
template <typename T>
class B {public: typedef T type;};
template <typename T>
class A {
void fn(typename T::type X);
//void fn(...){} // would prevent an error if T does not have type.
};
Basically you save the type in a typedef and then use that in A. This would error out of course if B does the T of A does not have T::type.
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.
I thought I could do something like this, but it doesn't work:
template <template <typename A,typename B> class C>
class Check
{
void Foo(A,B,C)
{
// 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 template
First, 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.