Specialization of a class template with the given class - c++

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

Related

If template parameter AA is a templatized class A<T> itself, is it possible to get the template parameter (T) of this templatized class?

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;

Use nested class of templated class as template template parameter in C++

In C++, I'd like to use a nested class inside a templated class as template template parameter. For non-nested classes the pattern is:
template<class T>
class A {
public:
T a;
// ...
};
template<class T, template<class ST> class S>
class B {
public:
S<T> b;
// ...
};
B<int, A> b;
Now I'd like to add a nested class to A and use this nested class as template template parameter S of class B, like this:
template<class T>
class A {
public:
class AA {
public:
T aa;
// ...
};
// ...
};
template<class T, template<class ST> class S>
class B {
public:
S<T> b;
// ...
};
B<int, A> b1; // ok
B<int, A::AA> b2; // error
B<int, A<int>::AA> b3; // error
I understand that the declarations of b2 and b3 are errors because A::AA is incomplete and A<int>::AA is not a template.
I would like to be able to declare something similar to b2. The idea is that A and B should both use the same class T.
I would like to be able to declare a number of classes similar to A with individually named sub-classes. Another use of this I can think of are multiple sub-classes of A that can be used as template template parameter to B.
One workaround I see is to refrain from using individual names on the sub-classes of A, use the b1 declaration (use A as template template parameter S for B) and change the implementation of B accordingly (i.e. use S::AA<T> instead of S<T>):
template<class T, template<class ST> class S>
class B {
public:
S::AA<T> b;
// ...
};
B<int, A> b;
The other workaround I see is to reduce the template template parameter of class B to a simple template parameter, and ensure the same T by other means.
Is there some other possibility? If yes, how?
Edit: Added forgotten class in template for B and changed template template parameter name to ST.
This works for me:
template<class T>
class A {
public:
class AA {
public:
T aa;
// ...
};
// ...
};
template<class T, template<class ST> class S >
class B {
public:
S<T> b;
// ...
};
template<class T> using NestedAA = typename A<T>::AA;
int main()
{
B<int, NestedAA> b; // ok
return 0;
}
If for any reason you are constrained to C++03, type aliases won't be available to you. You can then replace the "using" statement with the following definition for NestedAA:
template<class T>
class NestedAA : public A<T>::AA
{
};
You may create an template alias:
template <typename T>
using innerAA = typename A<T>::AA;
and then
B<int, innerAA> b42;
Demo
Assuming you only want the nested case to work, and since AA itself is not a template you could just drop the template for B's 2nd parameter like so:
template<class T>
class A {
public:
class AA {
public:
T aa;
// ...
};
// ...
};
template<class T, class S>
class B {
public:
S b;
// ...
};
//B<int, A> b1; // error
B<int, A<int>::AA> b2; // ok
PS Your original declaration of B needs an extra 'class' to compile on g++ 5.4
template<class T, template<class T> class S>

How to use friend keyword for template class

lets say that I have 2 template classes, A and B. If I want to make B a friend of A, what would I say ?
class<template T>
class A
{
public:
friend class B<T>; // ???
};
class<template T>
class B
{
};
To use a symbol, it must be declared or defined, this is the same in template. You need to forward declare template B. Also your syntax(class<template T>) to declare template class is not valid, it should be template <class T>.
This should work:
template <typename T> // typename can be replaced with class
class B;
template <typename T>
class A
{
public:
friend class B<T>;
};
template <typename T>
class B
{
};

Template weirdness

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.

No class template named X in templated class

When tryin to compile this (CRTP-like) code with GCC 4.6.0:
template<template<class> class T> struct A;
template<class T>
struct B: A<B<T>::template X> {
template <class U> struct X { U mem; };
};
B<int> a;
I get the errormessage "test.cpp:3:26: error: no class template named ‘X’ in ‘struct B<int>’". Why does X seem to be invisible outside the class definition?
As Emile Cormier correctly points out here the problem is that at the place of instantiation of A, B is still an incomplete type, and you cannot use the inner template.
The solution for that is moving the template X outside of the template B. If it is independent of the particular instantiation T of the template B, just move it to the namespace level, if it is dependent on the instantiation, you can use type traits:
template <typename T>
struct inner_template
{
template <typename U> class tmpl { U mem; }; // can specialize for particular T's
};
template <typename T>
struct B : A< inner_template<T>::template tmpl >
{
};
struct B is still considered an incomplete type when you specify A<B<T>::template X> as the base class.
You're trying to use a member of B as a parent of B creating a recursive-esque situation. For example this doesn't compile either:
template<template<class> class T> struct A {};
struct B : public A<B::nested>
{
struct nested {};
};