Template class arguments as type - c++

I have a class
template<typename T, typename U>
class A {
T i;
}
And i have a class B that should use the same types as class A
template<typename A_Type>
class B
: public A_Type
{
T j; // here I need a class member of the same type as the first type of A_Type (T from class A)
}
So I would need something like
template<typename A_Type<T, U>>
class B
: public A_Type
{
T j;
}
This notation is obviously not working but is there a notation that would fit my needs?

You can provide a member alias in A :
template<typename T, typename U>
class A {
T i;
using value_type = T;
};
template<typename A_Type>
class B
: public A_Type
{
typename A_Type::value_type;
};
Or use specialization to deduce the type of the argument:
template<typename T, typename U>
class A {
T i;
using value_type = T;
};
template<typename A_Type>
class B : public A_Type {};
template <typename T,typename U>
class B<A<T,U>> : A<T,U> {
T j;
};
As mentioned in comments, try to be careful with terminology. Using the terms right avoids issues. Neither A nor B are classes. They are class templates. And the member alias should be protected (or placed in a seperate trait template <typename A> struct get_T_from_instantiation_of_A;)

Can't you just pass that type ?
template<typename A_Type, typename T>
class B
: public A_Type
{
T j; // here I need a class member of the same type as the first type of A_Type (T from class A)
}

You could create some type traits to help out.
First one to test if a type is really an A type:
#include <type_traits>
template<class T>
struct is_A_type {
static std::false_type test(...);
template<template<class...> class U, class... V,
std::enable_if_t<std::is_same_v<U<V...>, A<V...>>, int> = 0>
static std::true_type test(const U<V...>&);
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template<class T>
inline constexpr bool is_A_type_v = is_A_type<T>::value;
Then a trait to get the type of the first template parameter:
template<class T>
struct first_type {
static void test(...);
template<template<class...> class U, class F, class... V>
static auto test(const U<F, V...>&) -> F;
using type = decltype(test(std::declval<T>()));
};
template<class T>
using first_type_t = typename first_type<T>::type;
These traits could then be used like so:
template<class A_Type>
class B : public A_Type {
static_assert(is_A_type_v<A_Type>, "A_Type must be an A type");
using T = first_type_t<A_Type>;
T j;
};

Related

Partial specialized template class (for container class type) is not called

I am still working on this problem I posted some hours before:
[How to overload/specialize template class function to handle arithmetic types and a container-class
I tried to implement this solution. It compiles but the object is created with the DerivedClass-Constructor instead of the partial specialized template class DerivedClass< Eigen::ArrayBase >
Do you have an Idea where I made a (or some) misstakes?
template <typename T> class BaseClass
{
protected:
T mem;
public:
BaseClass(T arg) : mem(arg){};
};
template <typename T> class DerivedClass : public BaseClass<T>
{
public:
DerivedClass(T arg): BaseClass<T>(arg){};
};
template <typename T>
class DerivedClass<Eigen::ArrayBase<T> >
: public DerivedClass<Eigen::ArrayBase<T> >
{
public:
DerivedClass(Eigen::ArrayBase<T> arg):BaseClass<Eigen::ArrayBase<T> >(arg){};
};
int main
{
...
Eigen::Array3d arg = Array3d::Random(3);
DerivedClass<Eigen::Array3d> o(arg);
....
}
template<template<class...>class Z>
struct template_instance_test {
static std::false_type test(...);
template<class...Ts>
static std::true_type test( Z<Ts...> const* );
template<class X>
using tester = decltype(test( std::declval<X*>() ) );
};
template<template<class...>class Z, class T>
using is_derived_from_template = typename template_instance_test<Z>::template tester<T>;
we can now ask if something is an instance of a particular template, or derived from an instance of a particular template.
template<class X>
struct Base {};
template<class X>
struct Derived:Base<X> {};
template<class T>
struct Storage {
T data;
};
template<class T, class=void>
struct Instance:Storage<T> {
enum {is_special = false};
};
template<class T>
struct Instance<T, std::enable_if_t< is_derived_from_template<Base, T>{} > >:
Storage<T> {
enum { is_special = true };
};
int main() {
Instance<int> i; (void)i;
static_assert(!Instance<int>::is_special);
Instance<Derived<int>> j; (void)j;
static_assert(is_derived_from_template<Base, Base<int>>{});
static_assert(is_derived_from_template<Base, Derived<int>>{});
static_assert(Instance<Derived<int>>::is_special);
}
and we are done. Live example.
Your code should works if Eigen::Array3d is an alias (through using or typedef) of Eigen::ArrayBase<T> for some T.
But I suppose that Eigen::Array3d inherit from Eigen::ArrayBase<T>. So isn't a ``Eigen::ArrayBase`, so doesn't matches the partial specialization, so matches the main template.
If you want a specialization that intercept all classes derived from Eigen::ArrayBase, a possible solution is add an additional template parameter with a default value and activate the specialization only it T derive from some Eigen::ArrayBase.
Something as follows (caution: code not tested)
constexpr std::false_type isArray (...);
template <typename T>
constexpr std::true_type isArray (Eigen::ArrayBase<T> const *);
template <typename T, typename = std::true_type>
class DerivedClass : public BaseClass<T>
{
public:
DerivedClass(T arg): BaseClass<T>(arg){};
};
template <typename T>
class DerivedClass<T, decltype(isArray(std::declval<T*>())>
: public DerivedClass<T>
{
public:
DerivedClass (T arg) : BaseClass<T>(arg){};
};

How do I declare SFINAE class?

Something is not working quite well for me. Is this the way to declare a class, that accepts only floating point template parameter?
template <typename T, swift::enable_if<std::is_floating_point<T>::value> = nullptr>
class my_float;
I fail to define methods outside this class. Doesn't compile, not sure why
Well... not exactly SFINAE... but maybe, using template specialization? Something as follows ?
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T>
class my_float<T, true>
{
// ...
};
If you really want use SFINAE, you can write
template <typename T,
typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
class my_float
{
// ...
};
or also (observe the pointer there isn't in your example)
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
class my_float // ------------------------------------------------^
{
};
-- EDIT --
As suggested by Yakk (thanks!), you can mix SFINAE and template specialization to develop different version of your class for different groups of types.
By example, the following my_class
template <typename T, typename = void>
class my_class;
template <typename T>
class my_class<T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
// ...
};
template <typename T>
class my_class<T,
typename std::enable_if<std::is_integral<T>::value>::type>
{
// ...
};
is developed for in two versions (two different partial specializations), the first one for floating point types, the second one for integral types. And can be easily extended.
You can also use static_assert to poison invalid types.
template <typename T>
class my_float {
static_assert(std::is_floating_point<T>::value,
"T is not a floating point type");
// . . .
};
It's a little bit more direct, in my opinion.
With either of the other approaches, e.g.
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T> class my_float<T, true> { /* . . . */ };
my_float<int,true> is a valid type. I'm not saying that that's a bad approach, but if you want to avoid this, you'll have to encapsulate
my_float<typename,bool> within another template, to avoid exposing the bool template parameter.
indeed, something like this worked for me (thanks to SU3's answer).
template<typename T, bool B = false>
struct enable_if {};
template<typename T>
struct enable_if<T, true> {
static const bool value = true;
};
template<typename T, bool b = enable_if<T,is_allowed<T>::value>::value >
class Timer{ void start(); };
template<typename T, bool b>
void Timer<T,b>::start()
{ \* *** \*}
I am posting this answer because I did not want to use partial specialization, but only define the behavior of the class outside.
a complete workable example:
typedef std::integral_constant<bool, true> true_type;
typedef std::integral_constant<bool, false> false_type;
struct Time_unit {
};
struct time_unit_seconds : public Time_unit {
using type = std::chrono::seconds;
};
struct time_unit_micro : public Time_unit {
using type = std::chrono::microseconds;
};
template<typename T, bool B = false>
struct enable_if {
};
template<typename T>
struct enable_if<T, true> {
const static bool value = true;
};
template<typename T,
bool b = enable_if<T,
std::is_base_of<Time_unit,
T>::value
>::value>
struct Timer {
int start();
};
template<typename T, bool b>
int Timer<T, b>::start() { return 1; }
int main() {
Timer<time_unit_seconds> t;
Timer<time_unit_micro> t2;
// Timer<double> t3; does not work !
return 0;
}

Detect common base class

Suppose one has a class hierarchy, without multiple inheritance:
struct TOP{};
struct L : TOP{};
struct R : TOP{};
struct LL : L{};
struct LR : L{};
struct RL : R{};
struct RR : R{};
Is it possible to write a metafunction that will return the type of the common base of two types? (it could return void if not common base class exists.)
For example
common_base<RR, R>::type == R
common_base<RL, RR>::type == R
common_base<LL, RR>::type == TOP
common_base<LL, std::string>::type == void
Obviously this wouldn't work with multiple inhertance, but I am focused in the the single inheritance case.
First, it doesn't seem to be possible without some introspection of the base class. So, I have this easier problem, do it in such a way that each clase knows its base (by an internal base type), for example:
struct LR : L{using base = L;};
Even in this way, I cannot seem to get the metaprogramming right.
Also I read somewhere (I can't find it now) that GCC has some extensions to detect common base class. Is that the case?
There was at some point bases and direct_bases in std::tr2 but that wasn't included. Some versions of gcc have it. Using these perhaps you can get what you want.
If you have each class alias the base as base (like below), it can be done.
struct Child : Parent { using base = Parent; }; //typedef works too
I created a struct:
template <class T1, class T2>
struct CommonBase;
CommonBase works by comparing every base of T2 to T1. When it reaches the top level base, it starts at the bottom again, but compares against the base of T1.
For example: CommonBase<RL, RR> would go through the following checks:
RL != RR
RL != R
RL != Top
R != RR
R == R
So CommonBase<RL, RR>::type == R. If there is no common base, type == void.
I put the code at the end because template metaprogramming is so pretty:
#include <type_traits>
template <class T>
struct GetBase //type = T::base, or else void
{
template <class TT> static typename TT::base& f(int);
template <class TT> static void f(...);
typedef std::remove_reference_t<decltype(f<T>(0))> type;
};
template <class T1, class T2>
struct Compare2 //Compares T1 to every base of T2
{
typedef typename GetBase<T2>::type _type;
template <class T, bool = !std::is_same<T, void>::value>
struct helper
{
typedef typename Compare2<T1, T>::type type;
};
template <class T>
struct helper<T, false>
{
typedef void type;
};
typedef typename helper<_type>::type type;
};
template <class T>
struct Compare2<T, T>
{
typedef T type;
};
template <class T1, class T2>
struct Compare1 //Uses Compare2 against every base of T1
{
typedef typename GetBase<T1>::type _type;
template <class T, bool = !std::is_same<T, void>::value>
struct helper
{
typedef typename Compare1<T, T2>::type type;
};
template <class T>
struct helper<T, false>
{
typedef void type;
};
typedef std::conditional_t<std::is_same<typename Compare2<T1, T2>::type, void>::value, typename helper<_type>::type, typename Compare2<T1, T2>::type> type;
};
template <class T>
struct Compare1<T, T> //Probably redundant
{
typedef T type;
};
template <class T1, class T2>
struct CommonBase //You can throw a std::enable_if on this to limit it to class types
{
typedef typename Compare1<T1, T2>::type type;
};
Here you can see it on some test cases.

How to filter a variadic template pack by type derivation?

I have a template class receiving multiple types, each type received is subclass of one of two options.
I want to expand them differently depending the parent class identifying each of them. This is equivalent to implement "filter" over the variadic template parameters.
For example:
class A{};
class B{};
template<class... C>
struct F{
std::tuple<types_derived_by<A, C>...> fn(types_subclassing<B, C>...){}
};
The types_derived_by template function should produce a variadic template pack with all the types in C that are derived from A, or B.
For example:
struct DA : public A{};
struct DB : public B{};
int main(){
F<DA, DB> f;
//f has a member function: DA fn(DB);
}
I'm using C++11, but I'm ok to move to c++14 if necessary.
You may do something like:
template <template <typename> class Pred, typename TUPLE, typename Res = std::tuple<>>
struct Filter;
template <template <typename> class Pred, typename Res>
struct Filter<Pred, std::tuple<>, Res>
{
using type = Res;
};
template <template <typename> class Pred, typename T, typename ... Ts, typename ... TRes>
struct Filter<Pred, std::tuple<T, Ts...>, std::tuple<TRes...>> :
Filter<Pred,
std::tuple<Ts...>,
std::conditional_t<Pred<T>::value,
std::tuple<TRes..., T>,
std::tuple<TRes...>>>
{
};
and then:
class A {};
template <typename T>
using is_base_of_A = std::is_base_of<A, T>;
class B {};
struct DA : public A{};
struct DB : public B{};
struct DA1 : public A{};
static_assert(std::is_same<std::tuple<DA, DA1>,
Filter<is_base_of_A, std::tuple<DA, DB, DA1>>::type>::value,
"unexpected");
Demo
If you don't mind using tuples as return value and parameter this might be a solution for you:
template <typename Base, typename...T>
struct base_filter;
template <typename Base>
struct base_filter<Base>
{
using type = std::tuple<>;
};
template <typename Base, typename T1>
struct base_filter<Base, T1>
{
using type = typename std::conditional_t<std::is_base_of<Base, T1>::value, std::tuple<T1>, std::tuple<>>;
};
template <typename Base, typename T1, typename...T>
struct base_filter<Base, T1, T...>
{
using type = decltype(std::tuple_cat(base_filter<Base, T1>::type(), base_filter<Base, T...>::type()));
};
//###########################################################
class A {};
class B {};
template<class...C>
struct F {
typename base_filter<A, C...>::type fn(typename base_filter<B, C...>::type){}
};
struct DA : public A {};
struct DB : public B {};
struct DA1 : public A {};
struct DA2 : public A {};
struct DB1 : public B {};
struct DB2 : public B {};
int main() {
std::tuple<DB> b;
F<DA, DB> f1;
std::tuple<DA> a = f1.fn(b);
std::tuple<DB1, DB2> bb;
F<DB1, DA1, DB2, DA2> f2;
std::tuple<DA1, DA2> aa = f2.fn(bb);
}

Use a template template parameter with CRTP in a Concept

I want to write a concept that tests for inheritance from a base class.
My Base class is publicly inherited by Derived classes, using CRTP.
This code works fine:
#include <type_traits>
namespace NS
{
template<typename D>
class Base {
// ...
};
class Derived : public Base<Derived>
{
public:
constexpr Derived() = default;
// ...
};
}
template<typename D>
concept bool inheritsFromB() {
return std::is_base_of<NS::Base<D>, D>::value;
}
template<inheritsFromB b>
void myFunct() {};
int main() {
constexpr auto d = NS::Derived();
using dType = typename std::decay<decltype(d)>::type;
myFunct<dType>();
}
I hit a problem if I want to template Derived. Is this possible?
namespace NS
{
template<typename D, typename T>
class Base { ... };
template<typename T>
class Derived : public Base<Derived<T>, T>
{ // ...
// probably some using declaration for T?
};
}
template<template <typename> class D>
concept bool inheritsFromB() {
return std::is_base_of<NS::B<D<T>,T>, D<T>::value;
}
...
the obvious problem being that I have no T in my concept declaration.
Moreover, I'm pretty sure I can't declare
template<template <typename> class D, typename T>
concept bool inheritsFromB() {
...
}
because a concept requires one template parameter.
Edit - the Working Paper P0121R0 lists in section 8.3.5, p23, template<typename T, typename U> concept bool C3 = true;. Consequently, wherever I read a concept can take only one parameter was either outdated, wrong, or I read it lacking care. end edit
Can I access the other type(s) T that I need here? Is there an alternative way (it seems to me like the template type D would carry the information of what it's type T is, but I also can't use using T = typename D<T>::valueType;, because I need the T to specific the type of D<T>...)
I suspect the following trait should work:
#include <type_traits>
#include <utility>
namespace NS
{
template <typename D, typename T>
class Base {};
template <typename T>
class Derived : public Base<Derived<T>, T> {};
}
namespace detail
{
template <typename T, template <typename> typename D>
std::true_type is_derived_from_base(const ::NS::Base<D<T>,T>*);
std::false_type is_derived_from_base(void*);
}
template <typename T>
using is_derived_from_base = decltype(detail::is_derived_from_base(std::declval<T*>()));
template <typename T>
concept bool inheritsFromB()
{
return is_derived_from_base<T>{};
}
DEMO (without concepts)