通过模板和SFINAE支持多个类接口

时间:2019-06-03 20:55:12

标签: c++ sfinae

我有一个类,它是从第三方库中提供的类派生的。

在第三方库的两个版本之间,他们将一个类中的成员从私有提升为公共,但随后,他们弃用了一种访问成员的方法。示例:

// 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 个答案:

答案 0 :(得分:3)

嗯...给出了以下两个模板功能

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