July 7, 2011, 9:05 p.m.

posted by technodev

## Structure SelectionYou already know how to use metafunctions to affect the types of individual class members: template <class T> struct X { static int m1 = metafunction1<T>::type::value; typedef typename metafunction2<T>::type m2; int m4(typename metafunction3<T>::type p); ... }; In this example, metaprograms are computing the value of Structure selection involves pushing the variable part of the class structure into public base classes or base class templates and using a metaprogram to choose among them. To see how it works, let's fix a problem in template <class R, class F, class G> class compose_fg { public: compose_fg(F const& f, G const& g) : f(f), g(g) {} template <class T> R operator()(T const& x) const { return f(g(x)); } private: F f; G g; }; You may be wondering what sort of problem there could possibly be: compose_fg<float,std::negate<float>,float(*)(float)> so T operator()(const T& x) const { return -x; } In other words, it is an empty class. The C++ standard, though, says that every one of
One way to eliminate storage for empty classes might be to detect them (using the It's not transparent: Even empty classes can have nontrivial constructors and destructors, and if we don't store copies of `f`and`g`, the difference in`compose_fg`'s behavior could be surprising.To implement `operator()`we still need`F`and`G`objects; if they weren't stored we'd need to construct them somehow, and they might not have default constructors.
Fortunately, there's a better solution. Compilers may implement an Empty Base Optimization (EBO), which allows an empty base class to be placed at the same address as any other subobject, as long as no two distinct subobjects of the same type share an address. For example, compose_fg<float,std::negate<float>,float(*)(float)> might have had ideal size if template <class R, class F, class G> class compose_fg : F // if empty, F may overlap with g { public: typedef R result_type; compose_fg(F const& f, G const& g) : F(f), g(g) // initialize base with f {} template <class T> R operator()(T const& x) const { F const& f = *this; // retrieve F subobject return f(g(x)); } private: G g; }; Naturally, we can't use that structure for all The first step in applying structure selection is to delegate control over the variable part of the class structure. In this case, the way // base class template to be defined later template <class F, bool F_empty, class G, bool G_empty> class storage; template <class R, class F, class G> class compose_fg : storage< F,boost::is_empty<F>::value , G,boost::is_empty<G>::value >{ typedef storage< F,boost::is_empty<F>::value , G,boost::is_empty<G>::value > base; public: compose_fg(F const& f, G const& g) : base(f, g) {} template <class T> R operator()(T const& x) const { F const& f = this->get_f(); G const& g = this->get_g(); return f(g(x)); } }; Now we only need to write
template <class F, class G> class storage<F,false,G,false> // neither F nor G is empty { protected: storage(F const& f, G const& g) : f(f), g(g) {} F const& get_f() { return f; } G const& get_g() { return g; } private: F f; G g; }; template <class F, class G> class storage<F,false,G,true> // G is empty : private G { protected: storage(F const& f, G const& g) : G(g), f(f) {} F const& get_f() { return f; } G const& get_g() { return *this; } private: F f; }; template <class F, class G> class storage<F,true,G,false> // F is empty : private F { protected: storage(F const& f, G const& g) : F(f), g(g) {} F const& get_f() { return *this; } G const& get_g() { return g; } private: G g; }; template <class F, class G> class storage<F,true,G,true> // F and G are both empty : private F, private G { protected: storage(F const& f, G const& g) : F(f), G(g) {} F const& get_f() { return *this; } G const& get_g() { return *this; } }; Since the EBO is optional, there are no guarantees that any of this will make a difference. That said, by selecting among different bases, we've at least given the compiler the opportunity to optimize away the storage for empty subobjects, and most of them will take advantage of it (see the exercises for more information). You might also want to look at the Boost |

- Comment