There is a class template A, which is taking template class for its template parameter.
template <typename T> class A {}
template <typename T> class B {}
int main()
{
A<B<int>>();
return 0;
}
Can class template A deduces its template parameter(B int)'s template parameter(int)?
Or is there the other way to solve this problem? For example,
template <typename T<typename U>> class A {}
You can make A a template template:
template <template <typename> class T, typename Inner>
class A<T<Inner>> {};
template<class>struct inner{};
template<template<class...>class Z, class T, class...Ts>
struct inner<Z<T, Ts...>>{
using type=T;
};
template<class Z>
using inner_t=typename inner<Z>::type;
and inner_t<X> is the first template argument of X if it exists, and a substitution failure otherwise.
What you described is a template template:
template< template<typename> class T > class A {};
note the class before T has to be class, not typename.
Related
This example code generates expected a class template, got std::pair <_T1, _T2>. I tried using struct Struct <std::pair> {};, but then parameters T and M become undeducible. How to avoid this?
template <template <class...> class>
struct Struct {};
template <class T, class M>
struct Struct <std::pair <T, M>> {};
Depending of what you want
template <template <class...> class>
struct Struct {};
template <>
struct Struct <std::pair>
{
// Specialization
};
or
template <typename> struct Struct {};
template <typename First, typename Second>
struct Struct <std::pair<First, Second>>
{
// Specialization
};
That is not a valid specialization for your template.
The reason why is because std::pair<T, M> is a full specialization of the class template std::pair and therefore a class. Your template expects a class template parameter which is exactly what the compiler is telling you.
How can I retrieve the template a type was originally instantiated from?
I'd like to do the following:
struct Baz{};
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
using Template = get_template<SomeType>::template type<T>;
static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
I know I can achieve this through partial specialization, but this forces me to specialize get_template for every template I want to use it with:
template <typename T>
struct get_template;
template <typename T>
struct get_template<Foo<T>>
{
template <typename X>
using type = Foo<X>;
};
live example
Is there a way around this limitation?
You could do something like that, using a template template parameter (should work for templates with any number of type arguments):
template <typename T>
struct get_template;
template <template <class...> class Y, typename... Args>
struct get_template<Y<Args...>> {
template <typename... Others>
using type = Y<Others...>;
};
Then to get the template:
template <typename T>
using Template = typename get_template<SomeType>::type<T>;
As mentioned by #Yakk in the comment, the above only works for template that only have type arguments. You can specialize for template with specific pattern of type and non-type arguments, e.g.:
// Note: You need the first size_t to avoid ambiguity with the first specialization
template <template <class, size_t, size_t...> class Y, typename A, size_t... Sizes>
struct get_template<Y<A, Sizes...>> {
template <class U, size_t... OSizes>
using type = Y<U, OSizes...>;
};
...but you will not be able to specialize it for arbitrary templates.
DEMO (with Foo and std::pair):
#include <type_traits>
#include <map>
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
struct get_template;
template <template <class...> class Y, typename... Args>
struct get_template<Y<Args...>> {
template <typename... Others>
using type = Y<Others...>;
};
template <typename T>
using Template = typename get_template<SomeType>::type<T>;
static_assert(std::is_same<SomeType, Template<Bar>>::value, "");
static_assert(std::is_same<Foo<int>, Template<int>>::value, "");
using PairIntInt = std::pair<int, int>;
using PairIntDouble = std::pair<int, double>;
template <typename U1, typename U2>
using HopeItIsPair =
typename get_template<PairIntDouble>::type<U1, U2>;
static_assert(std::is_same<PairIntDouble, HopeItIsPair<int, double>>::value, "");
static_assert(std::is_same<PairIntInt, HopeItIsPair<int, int>>::value, "");
Not sure I got the question. Would this work?
#include<type_traits>
#include<utility>
template<typename V, template<typename> class T, typename U>
auto get_template(T<U>) { return T<V>{}; }
struct Baz{};
struct Bar{};
template <typename T>
struct Foo {};
using SomeType = Foo<Bar>;
template <typename T>
using Template = decltype(get_template<T>(SomeType{}));
int main() {
static_assert(std::is_same<Foo<Baz>, Template<Baz>>::value, "");
}
You can generalize even more (SomeType could be a template parameter of Template, as an example), but it gives an idea of what the way is.
I'd like to specialize a class template on the type template parameter of the template template parameter. Is it possible? If yes, what is the syntax?
#include <type_traits>
template <typename T>
struct X {};
// primary template
template<template<class> class C>
struct Z : std::false_type {};
// specialization on the template template parameter
template<>
struct Z<X> : std::true_type {}; // OK
// specialization on the type template parameter of the
// template template parameter
template <template<class> class C>
struct Z<C<int>> {}; // ERROR
Motivation: Let's assume that the template template parameter denotes Collections (e.g. std::vector, std::deque). And I want to specialize Z on std::vector but I am not interested about the type template parameter of std::vector, that's OK. Also I want to specialize on all Collection types, which holds an int.
This question is similar to the following questions, but they are either trying to specialize a function template
How to specialize a template with template-tempate parameters
Specialize a template with a template
or they are trying to specialize not on the template template parameter
Specialization and template template parameters
or there's no template template parameter in the primary template
Templated class specialization where template argument is a template
The following code compiles fine:
#include <type_traits>
template <typename T>
struct X {};
// primary template, no template template parameter
template<typename T>
struct Z : std::false_type {};
// specialization on the template template parameter with arbitrary T
template<typename T>
struct Z<X<T>> : std::true_type {};
// here's where you need the template template parameter
template <template<class> class C>
struct Z<C<int>> : std::true_type {};
int main()
{
static_assert(!Z<Z<double>>::value, "" );
static_assert( Z<Z<int >>::value, "" );
static_assert( Z<X<double>>::value, "" );
// static_assert( Z<X<int >>::value, "" ); // error: ambiguous
// partial specialization
}
In your code you give Z a template template parameter, even though that should be done for the specialization only. That's why your code does not compile.
This cannot work because in your code:
template<template<class> class C>
struct Z : std::false_type {};
template<>
struct Z<X> : std::true_type {};
Z expects class template as a parameter.
template <template<class> class C>
struct Z<C<int>> {};
Here you are are not specializing any of it's template arguments and trying to pass C<int> which is not a class template (C is a class template and is different than C<int> which is concrete type).
If your class has template parameter which is a class template and you want your class to behave differently for different types passed for the container you probably should do something like:
template<template <typename> class Container,typename Element>
struct MyStruct
{
Container<Element> generic_elements;
// ...
};
template<template <typename> class Container>
struct MyStruct<Container,int>
{
Container<int> special_int_container;
void special_int_things();
//...
};
A beginner question:
How to put a condition on a template in a multi-templated class:
I tried this:
template <class T, class U>
typename std::enable_if<...>
class foo
{
};
And this:
template <class T,
class U = std::enable_if<...>>
class foo
{
};
But they are not working. Any help would be appreciated :)
Declare an additional template parameter defaulted to void and specialize it with enable_if:
template <typename T, typename U, typename Enable = void>
class foo {};
template <typename T, typename U>
class foo<T, U, typename std::enable_if<...>::type>
{
};
template <
typename T,
template <class> class OwnershipPolicy = RefCounted, #1
class ConversionPolicy = DisallowConversion, #2
template <class> class CheckingPolicy = AssertCheck,
template <class> class StoragePolicy = DefaultSPStorage
>
class SmartPtr;
Q1> What is the syntax for the line #1
template <class> class OwnershipPolicy = RefCounted,
why it doesn't provide a parameter such as follows?
template <class T2> class OwnershipPolicy = RefCounted,
Q2> What is the difference between #1 and #2?
template <class> class OwnershipPolicy = RefCounted,
class ConversionPolicy = DisallowConversion,
Why one of these line have template<class> and the other doesn't?
template <class> class OwnershipPolicy is a template template argument. I.e. OwnershipPolicy is expected to be a template taking one (and only one) type argument. There's no name for that argument, because it's not needed, and you wouldn't be able to use it for anything anyway.
class ConversionPolicy is equivalent to typename ConversionPolicy, i.e. any ordinary type argument.
The difference lies in how you use it. For template template arguments, you provide only name of the template, which you can later use to instantiate concrete types. For typename, you need a concrete type:
template <typename A, template <typename> class B>
struct foo {};
template <typename T>
struct x {};
struct y {};
template <typename T, typename U>
struct z {};
// both of these are valid:
foo<x<int>, x> a;
foo<y, x> b;
// these are not:
foo<y, x<int>> c;
foo<y, y> d;
foo<y, z> e; // z has two template arguments, B must have only one
Worth noting that this idiom is called "policy-based design".