1

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);
....
}
teflon
  • 15
  • 3

2 Answers2

1

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){};
 };
max66
  • 65,235
  • 10
  • 71
  • 111
  • Mh, okay. My aim is to be able to calculate on all derived classes of Eigen::ArrayBase in this partial specialized template. Is there a approach to solve this? – teflon Nov 30 '18 at 18:55
  • @teflon - I suppose it's possible but Isn't clear to me how `Array3d` and `ArrayBase` are related (something as `Array3d : ArrayBase` ?) and what do you need to know in the partial specialization (the template parameter `T` of `ArrayBase`?) – max66 Nov 30 '18 at 18:59
  • @teflon - I've improved the answer adding an example that show how to specialize a class for classes derived from `ArrayBase` (but caution: I don't have an `Eigen` platform so I can't compile to verify it). – max66 Nov 30 '18 at 19:15
  • Yes, ArrayBase is the BaseClass of Array<> and Array3d is a typedef of Array<> I tried to implement the ArrayBase Example from this site: https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html – teflon Nov 30 '18 at 19:18
  • 1
    While academic, `std::false_type isArray (...);` called with a non-pod type is very underspecified by the standard. I'd use pointers instead of values, which solves that issue. – Yakk - Adam Nevraumont Nov 30 '18 at 19:56
  • @Yakk-AdamNevraumont - Everyday I learn something new about C++; i don't know if it's a good thing. Anyway, thanks as usual. – max66 Nov 30 '18 at 21:39
1
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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524