読者です 読者をやめる 読者になる 読者になる

Boost.Signals2 名前付きテンプレート引数

C++

Boost.Signals2のsignalクラスは、テンプレートパラメータがたくさんあり、後ろの方のパラメータを一部だけ指定するのはなかなか大変です。

namespace boost {
  namespace signals2 {

    template<typename Signature, 
             typename Combiner = boost::signals2::optional_last_value<R>, 
             typename Group = int, typename GroupCompare = std::less<Group>, 
             typename SlotFunction = boost::function<Signature>, 
             typename ExtendedSlotFunction = boost::function<R (const connection &, T1, T2, ..., TN)>, 
             typename Mutex = boost::signals2::mutex> 
      class signal;
  }
}

Boost.Signals2には、Boost.Parameterベースの名前付きテンプレート引数を指定する、signal_typeメタ関数があります。
デフォルト以外のテンプレート引数を使いたい場合にはこれを使うのがいいでしょう。


例として、signalクラスの最後のテンプレートパラメータであるMutexだけをカスタマイズしてみましょう。適当なスピンロッククラスを作って指定します。

#include <iostream>
#include <atomic>
#include <boost/signals2.hpp>

class spinlock {
private:
  typedef enum {Locked, Unlocked} LockState;
  std::atomic<LockState> state_;

public:
  spinlock() : state_(Unlocked) {}
  
  void lock()
  {
    // 現在の状態をLockedと入れ替える
    while (state_.exchange(Locked, std::memory_order_acquire) == Locked) {
      // busy-wait...アンロックされるまで待機
    }
  }

  void unlock()
  {
    // 値をUnlockedに更新
    state_.store(Unlocked, std::memory_order_release);
  }
};

int main()
{
    namespace signals = boost::signals2;
    namespace keywords = signals::keywords;

    // ミューテックスだけカスタマイズする
    using signal = signals::signal_type<void(int), keywords::mutex_type<spinlock>>::type;

    signal sig;
    sig.connect([](int x) { std::cout << x << std::endl; });

    sig(3);
}
3

signal_typeを使ってる行がそれです。boost::signals2::keywords名前空間に、signalクラスのための名前付きテンプレート引数キーワードが定義されているので、指定したい型をキーワードでラップして渡します。最後に::typeをとると、指定した一部のテンプレート引数以外がデフォルトで埋められたsignal型が返されます。


参照:
Class template signal_type - Boost Signals2 Library