Поддержка нескольких классов интерфейсов через шаблоны и SFINAE - PullRequest
2 голосов
/ 03 июня 2019

У меня есть класс, производный от класса, предоставленного в сторонней библиотеке.

Между версиями сторонней библиотеки они повысили член в одном из своих классов от частного к общему, но вдвижение, они устарели метод для доступа к члену.Пример:

// Old class
class A
{
    public:
        int &GetA() { return a;}
    private:
        int a;
};

// NewClass
class A
{
    public:
        int a;
};

В моем коде используется экземпляр A, но я хочу, чтобы мой код работал с любой версией, если кто-то не обновил библиотеку.

class B
{
   public:

   int & ReturnA() { return GetInnards(m_a);}

   private:
   A    m_a;

  // If m_a has a GetA member function call this:
  template(typename aType)
  int & GetInnards(aType &a) { return a.GetA(); }

  // If m_a does not have an GetA() member function, call this:
  template(typename aType)
  int & GetInnards(aType &a) { return a.m_a; }
};

Кажется, я должен быть в состоянии использовать SFINAE, но я что-то упускаю.

Кроме того, я ничего не могу проверить с помощью #ifdef, поэтому я не могу пойти по этому пути.Мне нужно определить, существует ли метод и является ли он открытым.

1 Ответ

3 голосов
/ 04 июня 2019

Хорошо ... учитывая несколько функций шаблона следующим образом

template <typename A>
constexpr auto hasGetA (A const &)
   -> decltype( std::declval<A>().GetA(), std::true_type{} );

template <typename ... Ts>
constexpr std::false_type hasGetA (Ts const & ...);

Вы можете написать свой метод

  template <typename aType>
  auto GetInnards (aType & a)
     -> std::enable_if_t<true == decltype(hasGetA(a))::value, int &>
   { return a.GetA(); }

  template <typename aType>
  auto GetInnards (aType & a)
     -> std::enable_if_t<false == decltype(hasGetA(a))::value, int &>
   { return a.a; }
...