Is it possible to generate a linear hierarchy from variadic template parameters? For example:
GenLinearHierarchy<A,B,C,D,...> linHierarchy;
Generates a hierarchy where A -> B -> C -> D -> ... -> Empty (where the -> symbol stands for inherits from).
Where the template parameters (template template... parameters) have signatures such as:
template <class Base, class Plate> class A;
Where Base is the class above A in the hierarchy and Plate is the 'most derived' class (for example D< E<...>, A<...> >).
So far I've been unsuccessful - starting to wonder whether I'm going in circles (I do keep running into cyclic problems).
Sorry about the confusion - here is a 'concrete solution' (one which I'm not too fond of):
// Linear Hierarchy
#include <iostream>
template <class Base, class Floor>
class D : public Base
{
public:
};
template <class Base, class Floor>
class C : public Base
{
public:
void Fire()
{
static_cast<Floor*>(this)->Handle();
}
};
template <class Base, class Floor>
class B : public Base
{
public:
void Handle()
{
std::cout << "Handled" << std::endl;
}
};
class _FINISH {};
class _START : public B<C<D<_FINISH, _START>, _START, _START> {};
int main()
{
typedef _START A;
A a;
a.Fire();
return 0;
}
So, I'm still looking for a 'GenLinearHierarchy' class which can generate something like above, but with an instatiation like this:
GenLinearHierarchy<B,C,D> linHierarchy;
Thanks :)
I don't think you can let Plate be the most derived type, as that would mean the overall type would have to have itself as one of its own template parameters. This is the closest I've gotten:
struct Empty {};
template <template <class> class Head, template <class> class... Tail>
struct GenLinearHierarchy
{
typedef Head<typename GenLinearHierarchy<Tail...>::type> type;
};
template <template <class> class Tail>
struct GenLinearHierarchy<Tail>
{
typedef Tail<Empty> type;
};
template <class Base> struct A : Base {};
template <class Base> struct B : Base {};
template <class Base> struct C : Base {};
template <class Base> struct D : Base {};
static_assert(std::is_same< typename GenLinearHierarchy<A,B,C,D>::type
, A<B<C<D<Empty>>>> >::value
, "");
EDIT I think I've got what you wished for. Good luck trying to read it. You've only got yourself to blame. :)
struct Empty {};
template <class MostDerived,
template <class, class> class Head,
template <class, class> class... Tail>
struct GenLinearHierarchyInner
{
typedef Head<typename GenLinearHierarchyInner<MostDerived,
Tail...>::type,
MostDerived> type;
};
template <class MostDerived,
template <class, class> class Tail>
struct GenLinearHierarchyInner<MostDerived, Tail>
{
typedef Tail<Empty, MostDerived> type;
};
template <template <class, class> class... Types>
struct GenLinearHierarchy : GenLinearHierarchyInner<GenLinearHierarchy<Types...>,
Types...>::type
{};
template <class Base, class> struct A : Base {};
template <class Base, class> struct B : Base {};
template <class Base, class> struct C : Base {};
template <class Base, class> struct D : Base {};
typedef GenLinearHierarchy<A,B,C,D> ABCD;
static_assert(std::is_base_of< A<B<C<D<Empty, ABCD>, ABCD>, ABCD>, ABCD>
, ABCD >::value
, "");
It's probably something like this...
template<typename T, typename... Args>
class GenLinearHierarchy : public T, public GenLinearHierarchy<Args...> {};
template<typename T>
class GenLinearHierarchy<T> : public T {};
Related
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){};
};
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);
}
I'm trying to assert that template parameter would be derived from some base class. But base class is generic and in the context of assertion there is no difference between any specialization types.
How can I assert, that template parameter were derived from generic of any specialized type?
I'm trying to write it as
base_generic:
template<typename T> struct base_generic{};
derived_generic:
template<typename T> struct derived_generic : public base_generic<T>{};
class with assertion:
template<typename Tsource, typename Tderived_generic>
struct encoder {
static_assert(std::is_base_of<base_generic<typename>, Tderived_generic>::value);
};
This code compiles, but assertion fails
You may create a trait for that, something like:
namespace detail
{
template <template <typename > class C>
struct is_base_of_any_helper
{
template <typename T>
std::true_type operator ()(const C<T>*) const;
std::false_type operator() (...) const;
};
}
template <template <typename > class C , typename T>
using is_base_of_any =
decltype(detail::is_base_of_any_helper<C>{}(std::declval<const T*>()));
Demo
Note that it will fail with some edge cases such as:
multiple bases C<Tx>
private inheritance of C<T>.
From commentary of #PiotrSkotnicki
template <template <typename...> class Base, typename Derived>
struct is_base_of_template
{
using U = typename std::remove_cv<Derived>::type;
template <typename... Args>
static std::true_type test(Base<Args...>*);
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
template <template <typename...> class Base, typename Derived>
using is_base_of_template_t = typename is_base_of_template<Base, Derived>::type;
This solution works fine, example.
you can use static_assert.
See: http://en.cppreference.com/w/cpp/language/static_assert
So for example, if you have a base class
template< typename T >
class Base<T> {};
and the derived one
template< typename T >
class Derived : public Base<T> {};
with your use case
template< typename Tsource, typename Tstorage >
class Test
{
std::static_assert( std::is_base_of< base<T>, TStorage >::value );
}
It is not possible to get T without adding it as a template parameter.
But with a simple trick, you get it. You have to add a typedef to Derived:
template< typename T >
class Derived : public Base<T>
{
public:
typedef T value_type;
};
And you can use it inside of the static assertion.
template< typename Tsource, typename Tstorage >
class Test
{
std::static_assert( std::is_base_of< base<TStorage::value_type>, TStorage >::value );
}
Since Tstorage is a Derived, it has the value_type field.
Is there a way to detect whether a class is a template class or a simple class at compile time?
Eg:
class A
{
public:
void GetValue()
{
return 10 (compile time check? "": "+ 10"); // just an example
}
};
class B : public A
{
};
template <class T>
class C : public A
{
};
You may create a traits for that:
template <typename T>
struct is_type_templated : std::false_type {};
template <template <typename...> class C, typename ... Ts>
struct is_type_templated<C<Ts...>> : std::true_type {};
Live example
Note that it doesn't handle templated value (as std::array<T, N>).
C++03 allows to create template class which inheritances from template parameters:
// c++03
struct NullType {};
template <class T0, class T1 = NullType, class T2 = NullType>
class Collector : public T0, public T1, public T2
{
};
template <class T0, class T1>
class Collector<T0, T1, NullType> : public T0, public T1
{
};
template <class T0>
class Collector<T0, NullType, NullType> : public T0
{
};
So
typedef Collector<A, B, C> X;
eqeals to
class X: public A, public B, public C {};
C++11 allows do it easier:
// variadic templates - great thing!
template <class ... Classes>
class C11_Collector :
public Classes ...
{
};
Wrapping collector must wraps template parameters before inheritence:
template <template <class> class Wrap, class T0, class T1 = NullType, class T2 = NullType>
class Wrapping_Collector : public Wrap<T0>, public Wrap<T1>, public Wrap<T2>
{
};
template <template <class> class Wrap, class T0, class T1>
class Wrapping_Collector<Wrap, T0, T1, NullType> : public Wrap<T0>, public Wrap<T1>
{
};
template <template <class> class Wrap, class T0>
class Wrapping_Collector<Wrap, T0, NullType, NullType> : public Wrap<T0>
{
};
So
typedef Wrapping_Collector<W, A, B> X;
eqeals to
class X: public W<A>, public W<B> {};
How implement Wrapping_Collector in more easer way by c++11?
Is it possible to just enforce Wrap<NullType> to be an empty class? Then you could just directly use
template <template <typename> class Wrap, typename... Types>
class Wrapping_Collector : public Wrap<Types>... {
//...
};
Alternatively, if a double-inheritance chain instead of direct multi-inheritance is fine, you could make Wrapping_Collector<Wrap, A, B...> derive from both Wrapping_Collector<Wrap, B...> and Wrap<A>:
template <template <typename> class Wrap, typename... Types>
class Wrapping_Collector;
// The normal case
template <template <typename> class Wrap, typename Head, typename... Rest>
class Wrapping_Collector<Wrap, Head, Rest...>
: public Wrapping_Collector<Wrap, Rest...>, Wrap<Head>
{
//...
};
// Ignore on NullType
template <template <typename> class Wrap, typename... Rest>
class Wrapping_Collector<Wrap, NullType, Rest...>
: public Wrapping_Collector<Wrap, Rest...>
{
//...
};
// Base case
template <template <typename> class Wrap>
class Wrapping_Collector<Wrap> {};
I believe you would do this in C++11:
// variadic templates - great thing!
template <template <class> class Wrap, class... Classes>
class C11_Wrapping_Collector : public Wrap<Classes>...
{
};