Search code examples
c++loopsvariadic-templatesbreak

C++ break variadic template parameter loop


is there a way break variadic template parameter loop early. For example, in the following code, I want to quit the process function after process b1 without calling ProcessInvoke function for the types of B2 and B3.

In the following code, class B1, B2, B3 inherits B with their unique IDs. the templated process function is able to handle B1, B2, B3 processing logic. However, the current implementation requires to loop all the template parameters. To improve efficiency, we want to break the loop on the first matched id.

Thanks.

#include <iostream>
#include <string> 
  
class A {
public:    
    virtual ~A() {}    
    virtual int GetID() const  = 0;
};
   
template <int ID_>
class B : public A {   
public:
    enum { ID = ID_ };

    int GetID() const override { return ID;}   
};
  
class B1 : public B<1> {
public:
    const std::string name_ = "B1";
};

class B2 : public B<2> {
public:
    const std::string name_ = "B2";
};

class B3 : public B<3> {
public:
    const std::string name_ = "B3";
};
  
template<class T>
void ProcessInvoke(const A &a)
{
    std::cout << "Check Type " << T::ID << std::endl;

    if (a.GetID() == T::ID) { 
        std::cout << "Process " << a.GetID() << " OK" << std::endl;
    }
}
    
template<class...T>
void Process(const A &a) {    
    int dummy[] = { 0, (ProcessInvoke<T>(a), void(), 0)... };       
    static_cast<void>(dummy);    
}

int main()
{
    B1 b1;
    B2 b2;
    B3 b3;

    Process<B1, B2, B3>(b1);

    return 0;
}

Solution

  • && is short-circuiting. For example join pack with && and return if it matched or not.

    template<class T>
    int ProcessInvoke(const A &a)
    {
        std::cout << "Check Type " << T::ID << std::endl;
        if (a.GetID() == T::ID) { 
            std::cout << "Process " << a.GetID() << " OK" << std::endl;
            return 0;
        }
        return 1;
    }
        
    template<class...T>
    void Process(const A &a) {
        (ProcessInvoke<T>(a) && ...); 
    }