Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Even if you don't end up using them now mixins and policy template arguments are very useful things to understand. In this case they are very similar. First, an array with a mixin base. I have used c++0x mutex rather than openmp but you should get the idea.</p> <pre><code>#include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;mutex&gt; template &lt;class value_t, class base_t&gt; class array_t : private base_t { std::vector&lt;value_t&gt; v_; public: array_t(size_t sz = 0) : v_ (sz) { } value_t get(size_t i) const { this-&gt;before_get(); value_t const result = v_[i]; this-&gt;after_get(); return result; } void set(size_t i, value_t const&amp; x) { this-&gt;before_set(); v_[i] = x; this-&gt;after_set(); } }; class no_op_base_t { protected: void before_get() const { } void after_get() const { } void before_set() const { } void after_set() const { } }; class lock_base_t { mutable std::mutex m_; protected: void before_get() const { std::cout &lt;&lt; "lock\n"; m_.lock(); } void after_get() const { std::cout &lt;&lt; "unlock\n"; m_.unlock(); } void before_set() const { std::cout &lt;&lt; "lock\n"; m_.lock(); } void after_set() const { std::cout &lt;&lt; "unlock\n"; m_.unlock(); } }; int main() { array_t&lt;double, no_op_base_t&gt; a (1); array_t&lt;double, lock_base_t&gt; b (1); std::cout &lt;&lt; "setting a\n"; a.set(0, 1.0); std::cout &lt;&lt; "setting b\n"; b.set(0, 1.0); std::cout &lt;&lt; "getting a\n"; a.get(0); std::cout &lt;&lt; "getting b\n"; b.get(0); return 0; } </code></pre> <p>Now the same class but using a policy argument approach rather than inheritance.</p> <pre><code>#include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;mutex&gt; template &lt;class value_t, class policy_t&gt; class array_t { policy_t policy_; std::vector&lt;value_t&gt; v_; public: array_t(size_t sz = 0) : v_ (sz) { } value_t get(size_t i) const { policy_.before_get(); value_t const result = v_[i]; policy_.after_get(); return result; } void set(size_t i, value_t const&amp; x) { policy_.before_set(); v_[i] = x; policy_.after_set(); } }; class no_op_base_t { public: void before_get() const { } void after_get() const { } void before_set() const { } void after_set() const { } }; class lock_base_t { mutable std::mutex m_; public: void before_get() const { std::cout &lt;&lt; "lock\n"; m_.lock(); } void after_get() const { std::cout &lt;&lt; "unlock\n"; m_.unlock(); } void before_set() const { std::cout &lt;&lt; "lock\n"; m_.lock(); } void after_set() const { std::cout &lt;&lt; "unlock\n"; m_.unlock(); } }; int main() { array_t&lt;double, no_op_base_t&gt; a (1); array_t&lt;double, lock_base_t&gt; b (1); std::cout &lt;&lt; "setting a\n"; a.set(0, 1.0); std::cout &lt;&lt; "setting b\n"; b.set(0, 1.0); std::cout &lt;&lt; "getting a\n"; a.get(0); std::cout &lt;&lt; "getting b\n"; b.get(0); return 0; } </code></pre> <p>In this case both are very similar. The important difference is that the mixin could define some methods to be virtual and allow you to change the behaviour of array by inheriting from it. As in the following:</p> <pre><code>template &lt;class value_t&gt; class mk_virtual_base_t { protected: void before_get() const { } void after_get() const { } void before_set() const { } void after_set() const { } virtual value_t get(size_t) const = 0; virtual void set(size_t, value_t) = 0; }; template &lt;class value_t&gt; class daily_wtf_contender_t : public array_t&lt;value_t, mk_virtual_base_t&lt;value_t&gt; &gt; { virtual value_t get(size_t) const { std::cout &lt;&lt; "surprise! get is virtual!\n"; return 0; } virtual void set(size_t, value_t) { std::cout &lt;&lt; "surprise! set is virtual!\n"; } }; </code></pre> <p>While there are some real cases where the mixin advantage is useful it is not that often. So when working with templates the policy approach is often the more appropriate. Policy arguments are used by the standard library in many places so there are some good examples for you to study.</p> <p>As for your question about "inherit interface, not implementation." Used carefully inheriting implementation is quite useful. Same goes for multiple inheritance. You just need to be judicious about when you use them.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload