Skip to content

Conversation

@rherilier
Copy link
Contributor

After discussion in #104, there are finally more than 3 versions of signc::signal_connect(...):

  • 1 for lambdas and std::function;
  • 1 using sigc::ptr_fun(...) for function pointers;
  • 1 using sigc::bind(sigc::ptr_fun<...>(...) for function pointers with partially or totally bound arguments;
  • 4 sigc::mem_fun(...) for methods (one for each the non-cv one and the 3 cv ones);
  • 4 sigc::bind(sigc::mem_fun<...>(...) for methods (for the same reason).

I think the test program can be used as a good showcase (instead of writing an example program) and I don't have any changes for the documentation yet.

But I face 2 problems (hence the WIP prefix):

  1. Clang does not accept the sigc::mem_fun(...) with overloaded methods while GCC does.
  2. Clang and GCC do not accept sigc::bind(sigc::mem_fun<...>(...) while they accept sigc::bind(sigc::ptr_fun<...>(...).

By GCC, I mean GCC 13.3 and 14.2 and for Clang, I used 16.0.6, 17.0.6, and 18.1.8.

For 1, the message is:

.../libsigcplusplus/sigc++/signal_connect.h:63:1: note: candidate template ignored: couldn't infer template argument 'T_obj2'
   63 | signal_connect(signal<T_return(T_arg...)>& signal, /**/ T_obj& obj, T_return (T_obj2::*fun)(T_arg...))
      | ^

and I can not find a way to get around it... I can only think that Clang consider implicit conversion while searching a candidate while GCC does not...

for 2, the messages are (for GCC):

.../libsigcplusplus/sigc++/signal_connect.h:131:1: note: candidate: ‘template<class T_return, class T_obj, class T_obj2, class ... T_unbound, class T_bound0, class ... T_boundn> sigc::connection sigc::signal_connect(signal<T_return(T_arg ...)>&, T_obj&, T_return (T_obj2::*)(T_unbound ..., T_bound0, T_boundn ...), T_bound0&&, T_boundn&& ...)’
  131 | signal_connect(signal<T_return(T_unbound...)>& signal, /**/ T_obj& obj, T_return (T_obj2::*fun)(T_unbound..., T_bound0, T_boundn...), T_bound0&& bound0, T_boundn&&... boundn)
      | ^~~~~~~~~~~~~~
.../libsigcplusplus/sigc++/signal_connect.h:131:1: note:   template argument deduction/substitution failed:
.../libsigcplusplus/tests/test_signal_connect.cc:128:23: note:   couldn’t deduce template parameter ‘T_obj2’
  128 |   sigc::signal_connect(signal, b, &bar::print, 1);
      |   ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~

and (for Clang):

.../libsigcplusplus/tests/test_signal_connect.cc:128:3: error: no matching function for call to 'signal_connect'
  128 |   sigc::signal_connect(signal, b, &bar::print, 1);
      |   ^~~~~~~~~~~~~~~~~~~~
.../libsigcplusplus/sigc++/signal_connect.h:131:1: note: candidate template ignored: couldn't infer template argument 'T_obj2'
  131 | signal_connect(signal<T_return(T_unbound...)>& signal, /**/ T_obj& obj, T_return (T_obj2::*fun)(T_unbound..., T_bound0, T_boundn...), T_bound0&& bound0, T_boundn&&... boundn)
      | ^

I can not figure what make one build and not the other...

So, this PR has 2 commits: the first with all but the sigc:bind versions (but still with problem 1), the second with the sigc:bind versions of sigc::signal_connect(...). To make the later fails, the calls to sigc::signal_connect(...) in test_signal_connect_partial_bind_method() and in test_signal_connect_total_bind_method() have to be uncommented.

Any feedback or hints are welcome

best regards

@rherilier
Copy link
Contributor Author

It seems that removing T_obj2 occurrences from my new functions solves my problems. As T_obj can only inherit from (or be equal to) T_obj2, a reference to a T_obj2 automatically accepts a T_obj object. So the use of T_obj2 is useless.

So, is it a problem if sigc::signal_connect(...) does not mimic sigc::mem_func which explicitly distinguish T_obj and T_obj2?

@kjellahl
Copy link
Contributor

Does anyone really need 11 overloaded sigc::signal_connect() functions?
Usually you can use sigc::signal::connect() directly. signal_connect() is meant
only for the rather unusual(?) cases where an overloaded function shall be connected.

If you don't need them yourself, I suggest you skip some of the signal_connect() overloads.

  • Can signal_connect(signal<T_arg...>& signal, T_fun&& fun) resolve
    any ambiguous call to signal::connect()? If not, it can be skipped.

  • Volatile functions are extremely unusual, aren't they? Skip the signal_connect()
    overloads for volatile methods.

  • If the overloads with std::bind() are too problematic, skip them.
    I didn't know it's legal to have two template parameter packs. Is it?
    (template<typename T_return, typename T_obj, typename T_obj2, typename... T_unbound, typename T_bound0, typename... T_boundn>)

Problem 1 (clang does not accept the overloads with sigc::mem_fun() is more
serious. Without at least one such signal_connect() it's hardly worth
implementing at all.

is it a problem if sigc::signal_connect(...) does not mimic sigc::mem_func which
explicitly distinguish T_obj and T_obj2?

No, I don't see why it would be a problem.

@rherilier
Copy link
Contributor Author

To be honest, I made the 11 overloaded versions for coherency purpose to meet (hopefully) all cases with only one function.

If you don't need them yourself, I suggest you skip some of the signal_connect() overloads.

I personally only need the ones for the overridden methods.

My project (which uses sigc++) already has some of those helper functions. So I don't really need them. I though they could be helpful to someone else.

  • Can signal_connect(signal<T_arg...>& signal, T_fun&& fun) resolve any ambiguous call to signal::connect()? If not, it can be skipped.

OK (and I had forgotten T_return, implicitly caught by T_arg...).

  • Volatile functions are extremely unusual, aren't they? Skip the signal_connect() overloads for volatile methods.

I discovered the meaning of volatile after have found that sigc::mem_fun support volatile cases.

So, I'll remove them too.

  • If the overloads with std::bind() are too problematic, skip them.

and

Problem 1 (clang does not accept the overloads with sigc::mem_fun() is more serious. Without at least one such signal_connect() it's hardly worth implementing at all.

I was unclear in my second message... sorry.

Removing T_obj2 from the template parameter list resolves the 2 problems (Clang with sigc::mem_fun() and the build error with the overloads for sigc::bind).

I didn't know it's legal to have two template parameter packs. Is it?

I encountered the GCC error inconsistent parameter pack deduction with ‘’ and ‘’ and it lead me to https://stackoverflow.com/questions/26994969/inconsistent-parameter-pack-deduction-with-variadic-templates

I'll do the fix and squash my commits into one.

Before I forget, what about the documentation update, do you have some hints?

@rherilier rherilier force-pushed the add-signal-connect-helpers branch from fdc28bb to c698633 Compare August 31, 2024 16:41
@rherilier
Copy link
Contributor Author

So, here are the 6 remaining overloaded sigc::signal_connect(...):

  • 1 for function pointers;
  • 1 for nonconst methods;
  • 1 for const methods;
  • 3 to support sigc::bind for the 3 aforementioned version.

tests have been reworked too.

@rherilier rherilier force-pushed the add-signal-connect-helpers branch from c698633 to e269218 Compare August 31, 2024 16:51
@rherilier
Copy link
Contributor Author

I had forgotten to remove the unneeded sigc::...

@kjellahl
Copy link
Contributor

kjellahl commented Sep 1, 2024

Have you tested your new code, including test_signal_connect.cc, with MSVC?
If you haven't got easy access to MSVC, meson and libsigc++ on a Windows machine,
(I haven't) you can use .github/workflows/meson-msvc.yml.

Add to sigc++/sigc++.h: #include <sigc++/signal_connect.h>.

The copyright year of the new files shall be 2024.

When I build with -Dwarnings=fatal, I get the errors:

../tests/test_signal_connect.cc:30:6: error: ‘void {anonymous}::fun(int, double)’ defined but not used [-Werror=unused-function]
   30 | void fun(int i, double d)
      |      ^~~
../tests/test_signal_connect.cc:20:6: error: ‘void {anonymous}::fun(double)’ defined but not used [-Werror=unused-function]
   20 | void fun(double d)
      |      ^~~

what about the documentation update, do you have some hints?

sigc::signal_connect() shall be members of the signal group. The documentation
of each overloaded function shall contain @ingroup signal. See signal.h and signal_base.h.

signal_base.h contains a comment starting with @defgroup signal Signals.
There you can add a paragraph or two about signal_connect(), describing when it
can be better than a direct call to signal::connect().

@rherilier rherilier force-pushed the add-signal-connect-helpers branch from e269218 to 5307029 Compare September 2, 2024 14:59
@rherilier
Copy link
Contributor Author

I don't have found a way to make MSVC accepts the sigc::signal_connect(...) with bound arguments. So I remove them.

And thanks you for the hints about the workflow and for the documentation.

I saw that Doxygen's @newin is used. I leave them to your discretion.

@rherilier rherilier changed the title WIP: Add signal connect helpers Add signal connect helpers Sep 2, 2024
…methods to signals

Those helper functions have 2 main usages:
* avoid writing template parameters in case of method or function overloading;
* wrap use of sigc::mem_fun or sigc::ptr_fun when possible.

unsupported cases:
* lambda functions;
* std::function (or alike);
* volatile functions;
* const? volatile methods;
* binding with sigc::bind.
@rherilier rherilier force-pushed the add-signal-connect-helpers branch from 5307029 to 33b8e68 Compare September 2, 2024 16:43
@rherilier
Copy link
Contributor Author

I had forgotten to write a test for const method with const object, but MSVC ends with the error no matching overloaded function found.

To make it work, the template parameter list must have a T_obj2 like in sigc::mem_fun.

But as Clang does not like it (the problem 1 in my first message), I have no choice to do this big #if/#else/#endif.

@kjellahl kjellahl merged commit b154e84 into libsigcplusplus:master Sep 3, 2024
@rherilier
Copy link
Contributor Author

thanks for all

@kjellahl
Copy link
Contributor

kjellahl commented Sep 3, 2024

I forgot to mention @newin. I'll add them.

It's worrying that different compilers require different sets of template parameters.
I wonder what will happen when people use other compilers or other versions of
gcc, clang and MSVC?

@rherilier
Copy link
Contributor Author

And Github's workflows only support GCC, Clang, MSVC, or MacOs's Clang flavour... no even ICC...

If you prefer to revert my PR to avoid such worries, don't hesitate ;)

I'll give a try with clang's folks.

@rherilier
Copy link
Contributor Author

Thanks for the minors changes I missed (and the @newin).

I opened the issue llvm/llvm-project#107111 for the compiler based #if/else/endif I introduced.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants