Template template parameter in C++ for class definition - c++

I would like to do be able to do something like this:
template <...>
class A
{
B<c> val;
c test;
};
A<std::vector<int> > test;
So that I can reuse a my template template parameter in the A class.
Is this possible?
I have managed to get it working using template specification like this:
#include <vector>
template <typename T>
class A
{
};
template<template<typename > class B, typename C>
class A<B<C> >
{
B<C> vec;
C val;
};
A<std::vector<int> > a;
Is there a better way?

A common way to extract the inner type is to use the following typetrait
template <typename T> struct inner_param;
template <template <typename, typename...> class C, typename T, typename ...Ts>
struct inner_param<C<T, Ts...>>
{
using type = T;
};
And then just:
using IntVector = vector<int>;
inner_param< IntVector >::type a;
a = 42;
cout<< a << endl;

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;

get first template parameter of a class

I have a class foo which takes two template parameters, what I want to do is defaulting the second parameter to the first template parameter of the first parameter if it exists. foo would look like
template<typename Class, typename T = typename first_template_parameter<Class>::type>
class foo
{
...
}
and if Class has been defined as template<typename A, typename B, ...> class bar I want T to be A. So for example foo<std::map<int, float>> would have Class = std::map<int, float> and T = int, foo<int, char> would have Class = int and T = char. How can I implement first_template_parameter?
Drilling down into the first template parameter requires a little bit of work involving specialization:
template<typename T> struct first_template_type;
template<template<typename T, typename ...> class t,
typename T, typename ...Args>
struct first_template_type<t<T, Args...>> {
typedef T type_t;
};
template<typename T>
using first_template_type_t=typename first_template_type<T>::type_t;
Once that's out of the way, the rest is pretty boring:
#include <map>
template<typename Class,
typename T = first_template_type_t<Class>>
class foo
{
public:
T bar;
};
foo<std::map<int, char>> Foo;
int *baz=&Foo.bar;

Template class specialization with a template template argument

#include <tuple>
#include <iomanip>
template <typename T, typename ...L>
struct foo{};
template <typename T>
struct bar{
using toto = T;
};
template <template<typename T, typename ...L> class F>
struct bar<F>{
using toto = T
};
int main(){
bar<foo<int,char,char>> a;
}
I want to specialize bar when the argument is a class that has at least one template argument <typename T, typename ...L>
I tried :
template <template<typename T, typename ...L> class F>
struct bar<F<T,L...>>{
using toto = T
};
and
template <template<typename , typename ...> class F, typename T, typename ...L>
struct bar<F<T,L...>>{
using toto = T
};
which may have made sense, but I couldn't get it right
You forgot a lot of stuff on your sample, syntactically speaking
template <typename T, typename... L>
struct foo{};
template <typename T>
struct bar {
using toto = T; // Semicolon missing
};
template <template<typename, typename...> class F, typename T, typename... L>
struct bar<F<T,L...>> { // Wrong pack expansion
using toto = T;
};
int main() { // () missing
bar< foo<int,char,char> > a; // Pass the parameters to foo since you're
// partially specializing bar to just do that
}
Example on ideone
Your ideone code just has a bunch of typographical errors:
struct bar<F<T,...L>>{
//should be
struct bar<F<T,L...>>{
//missing brackets
int main{
//missing semicolon
using toto = T
bar<foo, int,char,char> a;
//should be
bar<foo<int,char,char>> a;
There's a few syntatic issues here.
bar is a template that takes one type argument. So any partial or explicit specialization of bar must also take one type argument.
template <template<typename T, typename ...L> class F>
struct bar<F> {
Here, the T and L names are irrelevent, and really you're specializating on a template template. That doesn't match. You'd have to specialize on a specific instantiation of F:
template <template<typename , typename ...> class F,
typename T, typename... L>
struct bar<F<T, L...>> {
You're missing a semicolon:
using toto = T;
^^
Your declaration of main is missing parentheses:
int main() {
bar<foo<int,char,char>> a;
}

Applying partially applied template

Having a class like the A, is there a way to apply it to a template like this of B, with T2 set to some type C? But without creating another template class inheriting from A.
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
With C++11 using a template alias works:
template<typename T1, typename T2>
class A
{ };
template<template <typename T1> class T3>
class B
{ };
class C
{ };
template< typename T > using A1 = A< T, C >;
int main()
{
B< A1 > b;
}
without C++11, you are left with what you probably already know:
template< typename T > class A1 : A< T, C > {};
I will propose an alternative solution: do not use template template parameters.
If you write:
template <typename T> struct B {};
Then it can be used with A<int, int> or C<3> or even plain D.
Whilst it is possible to use template template parameters, it is general a bad idea. You should treat the template parameter of a class as an implementation detail and apply the golden rule: do not rely on implementation details.
If you need access to the type, somehow, then use an associated type (aka T::AssociatedType) or a trait (BTraits<T>::AssociatedType).
EDIT: dealing with multiple instantiations of the template template parameter.
Suppose we want to "erase" the template template parameter of such a class:
template <template <typename> class A>
struct Something {
template <typename T>
void doit() { A<T>::doit(); }
};
The C++ standard allocation model is to use an inner rebind structure:
template <typename T>
struct Simple {
template <typename U>
struct rebind { typedef Simple<U> type; };
};
template <typename T0, typename T1>
struct Multi {
template <typename U>
struct rebind { typedef Multi<U, T1> type; };
};
template <typename A>
struct Something {
template <typename T>
void doit() { typedef typename A::rebind<T>::type B; B::doit(); }
};
Note how you can use complex computations in rebind and nothing forces you in blindly passing the type received as parameter.
Whilst another (similar) solution is to ask for a factory (aka, the object passed itself cannot be used but it can build useful objects); for ease of use the C++ containers ask of their allocators that they be both usable in themselves and factories for other types.
Yes, you can do it using C++11's alias template:
template <typename T>
using AA = A<T, C>;
B<AA> b;
Live example

Specialization and template template parameters

I've the following:
template <template <typename, typename> class C, class T, class A >
class TTCTest
{
public:
TTCTest(C<T, A> parameter) { /* ... some stuff... */ }
C<T, A> _collection;
};
I want to ensure that the template is only instantiated where the T and A classes are of a specific type (path and allocator respectively).
For example:
...
list<path, allocator<path> > list1;
list<int, allocator<int> > list2;
TTCTest<list> testvar(list1); // ...should work
TTCTest<list> testvar(list2); // ...should not work
...
Is this possible and what is the syntax?
Regards,
Col
You can do that with partial specialisation, where you fail to provide an implementation for the non-specialised case.
For example:
template <template <typename, typename> class C, class T, class A >
class TTCTest;
template <template <typename, typename> class C>
class TTCTest<C, path, allocator<path> >
{
// ...
};
You can create trait class to constraint instantiations. For example, limit your TTCTest construction only to path type:
template<class T, class A> class path {};
template<class T, class A> class not_path {};
template<class T> class allocation {};
template<class T>
struct Testable;
template<class T, class A>
struct Testable<path<T,A> > {};
template <template <typename, typename> class C,
class T, class A >
class TTCTest
{
public:
TTCTest(C<T, A> parameter, Testable<C<T,A> > = Testable<C<T,A> >());
C<T, A> _collection;
};
void foo()
{
path<int, allocation<int> > p;
TTCTest<path, int, allocation<int> > t(p); // compiles
not_path<int, allocation<int> > np;
TTCTest<not_path, int, allocation<int> > t1(np); // fails
}
Edit:
Since you indicated later that all you might need is partial specialization, in which case it would look like this:
template <class T, class A >
class TTCTest<path, T, A>
{
public:
TTCTest(path<T, A> parameter);
path<T, A> _collection;
};