mixinsとポリシーテンプレート引数を使用しなくても、今すぐ理解するのは非常に便利なことです。この場合、彼らは非常に似ています。まず、mixinベースの配列。 OpenMPではなくC++ 0xのミューテックスを使用しましたが、そのアイデアを得るべきです。
#include <iostream>
#include <vector>
#include <mutex>
template <class value_t, class base_t>
class array_t : private base_t {
std::vector<value_t> v_;
public:
array_t(size_t sz = 0) : v_ (sz) { }
value_t get(size_t i) const
{
this->before_get();
value_t const result = v_[i];
this->after_get();
return result;
}
void set(size_t i, value_t const& x)
{
this->before_set();
v_[i] = x;
this->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 << "lock\n"; m_.lock(); }
void after_get() const { std::cout << "unlock\n"; m_.unlock(); }
void before_set() const { std::cout << "lock\n"; m_.lock(); }
void after_set() const { std::cout << "unlock\n"; m_.unlock(); }
};
int main()
{
array_t<double, no_op_base_t> a (1);
array_t<double, lock_base_t> b (1);
std::cout << "setting a\n";
a.set(0, 1.0);
std::cout << "setting b\n";
b.set(0, 1.0);
std::cout << "getting a\n";
a.get(0);
std::cout << "getting b\n";
b.get(0);
return 0;
}
今では同じクラスですが、継承ではなくポリシー引数のアプローチを使用しています。
#include <iostream>
#include <vector>
#include <mutex>
template <class value_t, class policy_t>
class array_t {
policy_t policy_;
std::vector<value_t> 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& 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 << "lock\n"; m_.lock(); }
void after_get() const { std::cout << "unlock\n"; m_.unlock(); }
void before_set() const { std::cout << "lock\n"; m_.lock(); }
void after_set() const { std::cout << "unlock\n"; m_.unlock(); }
};
int main()
{
array_t<double, no_op_base_t> a (1);
array_t<double, lock_base_t> b (1);
std::cout << "setting a\n";
a.set(0, 1.0);
std::cout << "setting b\n";
b.set(0, 1.0);
std::cout << "getting a\n";
a.get(0);
std::cout << "getting b\n";
b.get(0);
return 0;
}
この場合、どちらも非常に似ています。重要な違いは、mixinがいくつかのメソッドを仮想的に定義して、それを継承して配列の動作を変更できることです。次のように:
template <class value_t>
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 <class value_t>
class daily_wtf_contender_t : public array_t<value_t, mk_virtual_base_t<value_t> > {
virtual value_t get(size_t) const { std::cout << "surprise! get is virtual!\n"; return 0; }
virtual void set(size_t, value_t) { std::cout << "surprise! set is virtual!\n"; }
};
ミックスインの利点は、その多くの場合ではありません便利ですいくつかの実際の例がありますが。だから、テンプレートを使って作業するときには、ポリシーアプローチがしばしば適切です。ポリシーの引数は多くの場所で標準ライブラリによって使用されているので、あなたが勉強する良い例がいくつかあります。
"継承インターフェイス、実装ではありません。使用を慎重に継承することは非常に便利です。複数の継承にも同じです。あなたはそれらをいつ使うべきかについて賢明である必要があります。
「MyArray」テンプレートにポリシーパラメータを追加するのが好きかもしれません。 –