2
votes

I have a libsigc++ signal which is connected to a c++11 lambda.

sigc::signal<void, std::string> foo;

foo.connect([](string s) { cout << s << endl; });

foo.emit(string("Hello"));

I want to change the signal's return type from void to non-void

sigc::signal<int, std::string> foo;

foo.connect([](string s) { return s.size(); });

cout << foo.emit(string("Hello")) << endl;

This gives an error:

void value not ignored as it ought to be

Is this usage pattern possible with lambdas?

2

2 Answers

2
votes

See the mention of SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE here: https://developer.gnome.org/libsigc++/stable/group__slot.html#details

You should just need to put this near the top of your source file:

namespace sigc {
  SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
}

Hopefully we'll make this unnecessary with future C++11-only versions of libsigc++.

You'll probably want to use sigc::track_obj() too: https://developer.gnome.org/libsigc++/unstable/group__track__obj.html#details

1
votes

Loong Jin provides a solution in this newsgroup posting.

Just put [this code] in a header somewhere and #include it when you want to use lambdas. It also allows you to throw std::function, boost::function, or any other object with an appropriate operator() at sigc::signals as well, since sigc::slot happily wraps them up now.

It still doesn't work with classes that have an overloaded operator(), but you can always use a lambda for those cases.

The code:

#include <type_traits>
#include <sigc++/sigc++.h>

namespace sigc
{
  template <typename Functor>
  struct functor_trait<Functor, false>
  {
    typedef decltype (::sigc::mem_fun(std::declval<Functor&>(),
                                      &Functor::operator())) _intermediate;
    typedef typename _intermediate::result_type result_type;
    typedef Functor functor_type;
  };
}

It'd be great if someone could explain why this works, as I would like to learn the mechanics at play here.