SFINAE和可变参数模板类

埃德温

我正在创建一个class C继承自可变数量的类。定义了这些类的列表,例如:A,B在function中,class C我需要从所有基类中调用函数,但是对象可以是C<A,B>C<A>否则C<B>,如果我将在中调用class Ain C<B>,则会出错。这是类的示例以及我尝试解决问题的方法:

    class A
    {
        int a;
    public:
        virtual void set_a(const int &value)
        {
            a = value;
        }
    protected:
        virtual int get_a()
        {
            return this->a;
        }
    };
    class B
    {
        int b;
    public:
        virtual void set_b(const int &value)
        {
            b = value;
        }
    protected:
        virtual int get_b()
        {
            return this->b;
        }
    };
    template<class ...T>
    struct Has_A
    {
        template<class U = C<T...>>
        static constexpr bool value = std::is_base_of < A, U > ::value;
    };

    template<class ...T>
    class C :
         virtual public T...
    {
    public:
    #define HAS_A Has_A<T...>::value

        void f()
        {
    #if HAS_A<>
            auto a = this->get_a();
    #endif
        auto b = this->get_b();
        cout << HAS_A<>;
    }
};

当我调用f()object时,C<A,B>它将跳过该调用,get_a()但输出为true

最初,我写了这个

template<class U = C<T...>>
typename std::enable_if<!std::is_base_of<A, U>::value, int>::type get_a()
{
    return -1;
}
template<class U = C<T...>>
typename std::enable_if<std::is_base_of<A,U>::value, int>::type get_a()
{
    return A::get_a();
}

但是我不想为A和的所有功能重写它B假设A还有10个功能。

有什么漂亮的解决方案吗?

PS对不起,我的英语。我以前从未使用过SFINAE。基本上,我有一堆基因,我想为它们编写方便的包装,在其中可以配置他希望生物体拥有的基因。

最高66

如果可以使用C ++ 17,则bipll的解决方案(if constexpr ())是(IMHO)更好的解决方案

否则,对于C ++ 11或C ++ 14,我不确定这是一个好主意,但我提出以下解决方案,因为在我看来,这很可笑(有些变态)。

首先,不是Has_A我提议一个更通用的isTypeInList

template <typename...>
struct isTypeInList;

template <typename X>
struct isTypeInList<X> : public std::false_type
 { };

template <typename X, typename ... Ts>
struct isTypeInList<X, X, Ts...> : public std::true_type
 { };

template <typename X, typename T0, typename ... Ts>
struct isTypeInList<X, T0, Ts...> : public isTypeInList<X, Ts...>
 { };

我也建议使用简单 indexSequence

template <std::size_t...>
struct indexSequence
 { };

令人鼓舞的std::index_sequence是(不幸的)仅从C ++ 14开始可用。

因此,在内部C<T...>,您可以定义模板using

  template <typename X>
  using list = typename std::conditional<isTypeInList<X, Ts...>{},
                                         indexSequence<0u>,
                                         indexSequence<>>::type;

使得list<A>indexSequence<0>如果A是的一部分T...可变参数列表中,indexSequence<>否则(空序列)。

现在,您可以编写f()该代码,只需调用一个辅助函数即可,该辅助函数f_helper()接收indexSequence所需检查的尽可能多的类型。

例如:如果您需要知道A并且B是否属于T...可变参数列表,则必须编写f()如下

  void f ()
   { f_helper(list<A>{}, list<B>{}); }

现在f_helper()可以是一个private函数,可以是

  template <std::size_t ... As, std::size_t ... Bs>
  void f_helper (indexSequence<As...> const &,
                 indexSequence<Bs...> const &)
   {
     using unused = int[];

     int a { -1 };
     int b { -1 };

     (void)unused { 0, ((void)As, a = this->get_a())... };
     (void)unused { 0, ((void)Bs, b = this->get_b())... };

     // do something with a and b
   }

这个想法是,As...0,如果A是在T...或空单,否则。

所以

int a { -1 };

a用假货的值初始化get_a()

(void)unused { 0, ((void)As, a = this->get_a())... };

a = this->get_a()AT...可变参数列表中(如果且仅当)才执行一次

该解决方案的有趣之处在于,a = this->get_a()A不在可变参数列表中,这不是问题如果As...列表为空,则不存在

下面是一个C ++ 11完全工作例子(其中,我在已经重命名Ts...T...可变参数序列C

#include <utility>
#include <iostream>
#include <type_traits>

class A
 {
   private:
      int a;

   public:
      virtual void set_a (int const & value)
       { a = value; }

   protected:
      virtual int get_a ()
       { std::cout << "get_a()!" << std::endl; return this->a; }
 };

class B
 {
   private:
      int b;

   public:
      virtual void set_b (int const & value)
       { b = value; }

   protected:
      virtual int get_b ()
       { std::cout << "get_b()!" << std::endl; return this->b; }
 };

template <typename...>
struct isTypeInList;

template <typename X>
struct isTypeInList<X> : public std::false_type
 { };

template <typename X, typename ... Ts>
struct isTypeInList<X, X, Ts...> : public std::true_type
 { };

template <typename X, typename T0, typename ... Ts>
struct isTypeInList<X, T0, Ts...> : public isTypeInList<X, Ts...>
 { };

template <std::size_t...>
struct indexSequence
 { };

template <typename ... Ts>
class C : virtual public Ts...
 {
   private:
      template <typename X>
      using list = typename std::conditional<isTypeInList<X, Ts...>{},
                                             indexSequence<0u>,
                                             indexSequence<>>::type;

      template <std::size_t ... As, std::size_t ... Bs>
      void f_helper (indexSequence<As...> const &,
                     indexSequence<Bs...> const &)
       {
         using unused = int[];

         int a { -1 };
         int b { -1 };

         (void)unused { 0, ((void)As, a = this->get_a())... };
         (void)unused { 0, ((void)Bs, b = this->get_b())... };

         // do something with a and b
       }

   public:
      void f ()
       { f_helper(list<A>{}, list<B>{}); }
 };


int main()
 {
   C<>     c0;
   C<A>    ca;
   C<B>    cb;
   C<A, B> cab;

   std::cout << "--- c0.f()" << std::endl;
   c0.f();
   std::cout << "--- ca.f()" << std::endl;
   ca.f();
   std::cout << "--- cb.f()" << std::endl;
   cb.f();
   std::cout << "--- cab.f()" << std::endl;
   cab.f();
 }

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章