c++ - How can I expand call to variadic template base classes? -
i have set of non-orthogonal policies, of them implementing common named method, policies add safety checks. want users able combine policies allow more complex validation without creating policies each combination case hand. approach creating new policy class combine others.
the simplified example below shows c combining class, here method id combined. expected result is, when calling id on c, sequentially call id of each base class.
#include <iostream> using namespace std; struct { void id() { cout << "a ";} }; struct b { void id() { cout << "b ";} }; template<class a, class... as> struct c : public a, public as... { void id() { a::id(); as...::id(); // line not work, illustrative. } }; int main() { c<a, b> c; c.id(); //expected: result b }
the question is: possible expand as... somehow without using recursive approach, using ... operator?
sure. need context permits pack expansion - simple 1 braced initializer list, has benefit of guaranteeing left-to-right evaluation:
using expander = int[]; (void) expander { 0, ((void) as::id(), 0)... };
...
expands pattern left; in case pattern expression((void) as::id(), 0)
.the
,
in expression comma operator, evaluates first operand, discards result, evaluates second operand, , returns result.- the
(void)
cast onas::id()
exists guard against overloadedoperator,
, , can omitted if sure none ofas::id()
calls return overloads comma operator. 0
on right hand side of comma operator becauseexpander
array ofint
s, whole expression (which used initialize element of array) must evaluateint
.- the first
0
ensures don't attempt create illegal 0-sized array whenas
empty pack.
demo.
in c++17 (if lucky), entire body of c::id
can replaced a binary fold expression: (a::id(), ... , (void) as::id());
demo.
Comments
Post a Comment