condition on a template in multi template class - c++

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>
{
};

Related

Alias that transforms a template type to the same type but templated on something different

I have a
template <typename T, typename U>
struct A;
and a
template <typename U>
struct B;
How do I make an alias that transforms an A<T, U> type to a A<T, B<U>> type? i.e. something that looks like this:
template <typename TypeA>
using ModifiedTypeA = TypeA<T, B<U>>; // <--- I don't know how to get T and U from TypeA
where ModifiedTypeA only needs to be templated on TypeA?
I was thinking that the above could be achieved if TypeA is always guaranteed to have member aliases
template <typename T_, typename U_>
struct A
{
using T = T_;
using U = U_;
};
and then do
template <typename TypeA>
using ModifiedTypeA = TypeA<typename TypeA::T, B<typename TypeA::U>>;
But is there another cleaner way + that doesn't make the above assumption?
Try
template <typename TypeA, template<typename> typename TemplateB>
struct ModifiedTypeAWtihImpl;
template <template<typename, typename> typename TemplateA,
typename T, typename U,
template<typename> typename TemplateB>
struct ModifiedTypeAWtihImpl<TemplateA<T, U>, TemplateB> {
using type = TemplateA<T, TemplateB<U>>;
};
template <typename TypeA, template<typename> typename TemplateB>
using ModifiedTypeAWtih = typename ModifiedTypeAWtihImpl<TypeA, TemplateB>::type;
Demo

Retrieve the template a type is instantiated from

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.

Deduce template parameter's template parameter

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.

Check if a class is equal to a template instance or a normal class

I have an integral_constant to determine if a class is in a provided list of classes:
template <typename T> using decay_t = typename std::decay<T>::type;
template <typename... Args> struct SOneOf : std::integral_constant<bool, false>
{
};
template <typename T1, typename T2, typename... Tail> struct SOneOf<T1, T2, Tail...>
: std::integral_constant<bool, SOneOf<T1, T2>::value || SOneOf<T1, Tail...>::value>
{
};
template <typename T1, typename T2> struct SOneOf<T1, T2>
: std::integral_constant<bool, std::is_same<decay_t<T1>, decay_t<T2>>::value>
{
};
template <typename T> struct SOneOf<T> : std::integral_constant<bool, false>
{
};
I also know that I can give templated classes as template arguments via template <template <typename> class T>.
Assuming I have two classes
template <typename T> class CClassA;
template <typename T> class CClassB;
and am in a function template <typename TF> function f().
How can I generically check if TF (e.g. int or CClassA<double>) is a CClassA or a CClassB or a float?
I'd like to achieve something like
SOneOf<TF, CClassA, CClassB, float>::value
If you're trying to get that information inside the function template you can use partial specialization:
template <bool...> struct bool_pack;
template <bool... B>
using any_true = std::integral_constant<bool,
!std::is_same<bool_pack<false, B...>, bool_pack<B..., false>>{}>;
namespace detail {
template <template <class...> class, typename>
struct IsSpec : std::false_type {};
template <template <class...> class T, typename... U>
struct IsSpec<T, T<U...>> : std::true_type {};
}
template <typename U, template <class...> class... T>
using IsSpecialization = any_true<detail::IsSpec<T, std::decay_t<U>>{}...>;
Usage would be simple:
static_assert( IsSpecialization<CClassB<int>, CClassA, CClassB>{}, "" );
static_assert( !IsSpecialization<void, CClassA, CClassB>{}, "" );
Demo. The extra comparison for float has to be done separately, e.g. via std:is_same.
If you need different code based on the template the type is a specialization of, use overloading.
template <typename Arg>
void f( CClassA<Arg> const& obj ) { /* … */ }
template <typename Arg>
void f( CClassB<Arg> const& obj ) { /* … */ }

Partial specialization friend declaration

In the following code:
template <typename U, typename V> class A {};
template <typename U, typename V> class B {};
template <typename T>
class C {
template <typename U, typename V> friend class A; // Works fine.
// template <typename U> friend class B<U,T>; // Won't compile.
};
I want B<U,T> to be friend to C<T>, that is, the second parameter of B must match C's parameter, though its first parameter can be anything. How do I achieve this? The friend declaration of A<U,V> is too much, though I will take that if I can't restrict it any further.
Perhaps define a meta-function
template <typename, typename = void> struct FriendTraits { struct type{}; };
or something like that within C?
The first 2 lines of
template <typename, typename = void> struct FriendTraits { struct type{}; };
template <typename U> struct FriendTraits<U,T> { using type = B<U,T> ; } ;
template <typename U> friend typename FriendTraits<U,T>::type;
compiled, but not the important 3rd line (because it is the same problem).