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

Supporting multiple class interfaces through templating and SFINAE

我有一个 class 派生自第三方库中提供的 class。

在第三方库的不同版本之间,他们将其中一个 classes 中的成员从私有提升为 public,但在此过程中,他们弃用了一种访问该成员的方法。示例:

// 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 测试任何东西,所以我不能走那条路。我需要检测方法是否存在,或者成员是否为 public.

嗯...给定几个模板函数如下

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