Specifying alternate defaults for boost signals2

386 views Asked by At

Boost's signals2 library defines a nice way to pass through alternate parameters for some of its extended functionality (via its Parameters library). When one of these alternate parameters is fairly commonplace in my code then I want to make a helper to simplify usage further; for example to specify an alternate mutex type I can do this:

namespace bs2 = boost::signals2;
template<typename Signature>
struct my_signal
{
    typedef typename bs2::signal_type<Signature,
        bs2::keywords::mutex_type<my_mutex> >::type type;
};

my_signal<void ()>::type some_signal;

Unfortunately by doing this I've also "lost" the ability to specify alternate values for the other signal parameters (such as combiner type), without going back to the verbose syntax or defining extra metafunctions such as my_signal_with_combiner or something (which seems silly). I don't think I can do that with a default template parameter value either since the default for Combiner requires breaking apart Signature to get the return type. (And ideally of course I'd like something that works for any of the other parameters, not just the combiner.)

So, the "real" question is: is there a (simple) way to define something like signal_type that behaves identically to it but has a different default value for one of the parameters? (Ideally, it shouldn't require changing if Boost.Signals2 adds more parameters in the future.)

(Also, no C++11 please. Still using an older compiler.)

1

There are 1 answers

0
Miral On

I've worked out the following, which appears to do the trick. Still interested in improved answers, though:

namespace bs2 = boost::signals2;

template <
    typename Signature,
    typename A1 = boost::parameter::void_,
    typename A2 = boost::parameter::void_,
    typename A3 = boost::parameter::void_,
    typename A4 = boost::parameter::void_,
    typename A5 = boost::parameter::void_,
    typename A6 = boost::parameter::void_
  >
struct my_signal_type : public bs2::signal_type<Signature, A1, A2, A3, A4, A5, A6>
{
    typedef typename boost::parameter::value_type<args, bs2::keywords::tag::mutex_type, my_mutex>::type mutex_type;

    typedef bs2::signal<
        signature_type,
        combiner_type,
        group_type,
        group_compare_type,
        slot_function_type,
        extended_slot_function_type,
        mutex_type
    > type;
};

template <
    typename Signature,
    typename A1 = boost::parameter::void_,
    typename A2 = boost::parameter::void_,
    typename A3 = boost::parameter::void_,
    typename A4 = boost::parameter::void_,
    typename A5 = boost::parameter::void_,
    typename A6 = boost::parameter::void_
  >
class MyEvent : public my_signal_type<Signature, A1, A2, A3, A4, A5, A6>::type
{
public:
    typedef typename my_signal_type<Signature, A1, A2, A3, A4, A5, A6>::type base_type;

    explicit MyEvent(const typename base_type::combiner_type& combiner = combiner_type())
        : base_type(combiner)
    {
    }
};

One thing that has me a little puzzled is why the use of "combiner_type" in the constructor requires explicit scoping in the type declaration -- and then that it doesn't for the default parameter. (Removing either "typename" or "base_type::" here triggers the standard "default-int" error (which means "that doesn't look like a type I know"). Which is odd, since it's defined in the base class. I'm guessing it's some weird template-partial-instantiation thing.