简体   繁体   English

可变参数模板类遍历类型

[英]Variadic template class iterate over types

I am attempting to create a variadic template class with a method that requires iterating over the template arguments and calling an unrelated template function with each type. 我试图用一种方法来创建可变参数模板类,该方法需要遍历模板参数并为每种类型调用不相关的模板函数。

The idea is for this templated class to be extended with specific template parameters in order to encapsulate the base behavior. 该模板类的想法是使用特定的模板参数进行扩展,以封装基本行为。

A simple example of the general idea would be this (terrible) Checker class: 一个简单的总体思路示例就是这个(可怕的) 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

In order for isOneOf to work, it needs to be able to iterate over the template arguments 为了使isOneOf正常工作,它需要能够遍历模板参数

I'm using a C++14 compiler and am not able to use boost . 我使用的是C ++ 14编译器, 无法使用boost

I suppose that a possible C++14 solution (but also C++11) is 我想可能的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;
 }

Unfortunately isn't shot circuiting (that is: all nullptr != dynamic_cast tests are evaluated (if the compiler doesn't optimize it) also when the first one is true). 不幸的是,当第一个为true时,就不会触发电路(即:评估所有nullptr != dynamic_cast测试(如果编译器未对其进行优化))。

If you can use C++17, with template folding all is simpler 如果您可以使用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;
  };
}

now: 现在:

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

With C++17, it should be possible to tinker with fold expressions and get this done in one shot. 使用C ++ 17,应该可以对折叠表达式进行修补,并一口气完成它。 But, with C++14, probably the most readable, if not the most terse, approach is to use a helper template class, and some specialization... 但是,对于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;
}

Resulting output: 结果输出:

0
1
1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM