- making a couple comparisons with an integer in the stack can be slightly faster sometimes that walking to a vtable, which would pay-off if the object methods are called many times
- the tradeoff of bigger stack space occupied by the extra-pointers and the extra-comparisons instead of a parametrized
Duff's device jump is unavoidable without compiler support of variadic parameter pack switch folds (not totally true, see final remarks)
Final remarks
Although lack of a switch fold expression makes life a bit harder, it's still possible to destructure several variadic specializations in order to provide switch-based apply implementations:
template <typename Interface, typename ImplFirst, typename ImplLast>
struct OpaqueImplCollector< Interface, ImplFirst, ImplLast> : public ImplRef<Interface, ImplLast, 0>,
public ImplRef<Interface, ImplFirst, 1>
{
using BaseImplRef0 = ImplRef<Interface, ImplLast, 0>;
using BaseImplRef1 = ImplRef<Interface, ImplFirst, 1>;
static constexpr int level = 1;
const int m_idx;
//template<typename >
OpaqueImplCollector(Interface* i) : BaseImplRef0(i), BaseImplRef1(i),
m_idx( (BaseImplRef1(i).instance() > -1) ? level : BaseImplRef0(i).instance() )
{}
inline int instance() const
{
return m_idx;
}
template<typename Functor>
decltype(std::declval<Functor>()(std::declval<Interface&>())) apply(Functor f)
{
assert(m_idx > -1);
switch( m_idx)
{
case 0:
return BaseImplRef0::apply(f);
case 1:
return BaseImplRef1::apply(f);
default:
assert(m_idx > -1);
}
}
};