簡體   English   中英

可變參數模板類遍歷類型

[英]Variadic template class iterate over types

我試圖用一種方法來創建可變參數模板類,該方法需要遍歷模板參數並為每種類型調用不相關的模板函數。

該模板類的想法是使用特定的模板參數進行擴展,以封裝基本行為。

一個簡單的總體思路示例就是這個(可怕的) Checker類:

class Arg {
    Arg() {};
    virtual ~Arg() = default;
};

class A : public Arg{ /* ... */ };
class B : public Arg{ /* ... */ };
class C : public Arg{ /* ... */ };

template <typename ... SubClasses>
class Checker {
public:

    Checker() {};
    virtual ~Checker() = default;

    bool isOneOf(Arg* base) const;
};


template <typename ... SubClasses>
bool Checker<SubClasses>::isOneOf(Arg* arg) const
{
    // NOTE: I don't know how I would iterate over the class types....
    for (auto SubClass : SubClasses...) { // <-- not valid code
        if (std::dynamic_cast<SubClass>(arg)) {
            return true;
        }
    }
    return false;
}

class Whatever : public Checker<A, B> {};

auto whatever = new Whatever();
auto a = new A();
auto b = new B();
auto c = new C();

whatever->isOneOf(a); // true
whatever->isOneOf(b); // true
whatever->isOneOf(c); // false

為了使isOneOf正常工作,它需要能夠遍歷模板參數

我使用的是C ++ 14編譯器, 無法使用boost

我想可能的C ++ 14解決方案(也是C ++ 11)是

template <typename ... SubClasses>
bool Checker<SubClasses...>::isOneOf (Arg * arg) const
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= (nullptr != dynamic_cast<SubClasses *>(arg))... };

   return ret;
 }

不幸的是,當第一個為true時,就不會觸發電路(即:評估所有nullptr != dynamic_cast測試(如果編譯器未對其進行優化))。

如果您可以使用C ++ 17,那么通過模板折疊,一切都將更加簡單

template <typename ... SubClasses>
bool Checker<SubClasses...>::isOneOf (Arg * arg) const
 { return (... || (nullptr != dynamic_cast<SubClasses *>(arg)) ); }
template<class T>struct tag_t{using type=T;};
template<class Tag>using type_t=typename Tag::type;

template<class F>
void foreach_arg(F&&f){
  return [f=std::forward<F>(f)](auto&&...args){
    int discard[]={0,(void(
      f(decltype(args)(args)
    ),0)...};
   (void)discard;
  };
}

現在:

bool isOneOf(Arg* base) const{
  bool r=false;
  foreach_arg( [&](auto tag){ r = r || dynamic_cast<type_t<decltype(tag)>>( base ); } )
  ( tag_t<SubClasses>{}... );
  return r;
}

使用C ++ 17,應該可以對折疊表達式進行修補,並一口氣完成它。 但是,對於C ++ 14,可能最易讀,甚至不是最簡潔的方法是使用幫助程序模板類,以及一些專門知識。

#include <iostream>

class Arg {

public:
    Arg() {};
    virtual ~Arg() = default;
};

template<typename ...Args> struct is_one_of_helper;

template<>
struct is_one_of_helper<> {

    static bool isOneOf(Arg *arg)
    {
        return false;
    }
};

template<typename A, typename ...Args>
struct is_one_of_helper<A, Args...> {

    static bool isOneOf(Arg *arg)
    {
        if (dynamic_cast<A *>(arg))
            return true;

        return is_one_of_helper<Args...>::isOneOf(arg);
    }
};

template <typename ... SubClasses>
class Checker {
public:

    Checker() {};
    virtual ~Checker() = default;

    bool isOneOf(Arg* base) const
    {
        return is_one_of_helper<SubClasses...>::isOneOf(base);
    }
};

class A : public Arg{ /* ... */ };
class B : public Arg{ /* ... */ };
class C : public Arg{ /* ... */ };

int main()
{
    Arg *a=new A;
    Arg *b=new B;
    Arg *c=new C;

    Checker<B, C> checker;

    std::cout << checker.isOneOf(a)
          << std::endl;

    std::cout << checker.isOneOf(b)
          << std::endl;

    std::cout << checker.isOneOf(c)
          << std::endl;
}

結果輸出:

0
1
1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM