Частично специализированный шаблонный класс (для контейнерного типа) не вызывается - PullRequest
0 голосов
/ 30 ноября 2018

Я все еще работаю над этой проблемой, которую я написал за несколько часов до этого: [ Как перегрузить / специализировать функцию класса шаблона для обработки арифметических типов и класса контейнера Я пытался реализовать это решение.Он компилируется, но объект создается с помощью DerivedClass-Constructor вместо частично специализированного шаблонного класса DerivedClass У вас есть идея, где я допустил (или некоторые) ошибки?

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);
....
}

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018
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>;

теперь мы можем спросить, является ли что-то экземпляром определенного шаблона или получено из экземпляра определенного шаблона.

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

и все готово. Живой пример .

0 голосов
/ 30 ноября 2018

Ваш код должен работать, если Eigen::Array3d является псевдонимом (через using или typedef) Eigen::ArrayBase<T> для некоторых T.

Но я предполагаю, что Eigen::Array3d наследуется от Eigen::ArrayBase<T>.Так что не `` Eigen :: ArrayBase``, поэтому не соответствует частичной специализации, поэтому соответствует основному шаблону.

Если вы хотите специализацию, которая перехватывает все классы, производные от Eigen::ArrayBase, aВозможное решение - добавить дополнительный параметр шаблона со значением по умолчанию и активировать только специализацию T, полученную из некоторого Eigen::ArrayBase.

Что-то следующее (осторожно: код не проверен)

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