Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template class + SFINAE member function with variadic template arguments #201

Open
taehyounpark opened this issue Nov 3, 2023 · 2 comments

Comments

@taehyounpark
Copy link

taehyounpark commented Nov 3, 2023

This is related to #192 which was displaying the issue inside a large library + older version of cppyy used by ROOT. I've managed to isolate the issue into a minimal example on the latest version of cppyy.

Python 3.11.4 (main, Jul  5 2023, 08:41:25) [Clang 14.0.6 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cppyy
>>> cppyy.__version__
'3.0.0'

The issue seems to be stemming from the fact that cppyy cannot handle a function that is:

  1. A member function of a template class, that
  2. Accepts a template parameter pack, and
  3. Is also overloaded via SFINAE depending on the class template parameter

This (as far as I know) is valid C++ according to both GCC and Clang, including whatever is being used by the backend of cppyy. Here is the illustration of the issue:

import cppyy

cppyy.cppdef('''
template <typename T> struct TestSfinae {
  template <typename U, typename V = T,
            std::enable_if_t<std::is_arithmetic_v<V>, bool> = false>
  auto test_single(U arg) {
    std::cout << "good" << std::endl;
    return 0;
  }
  template <typename... Args, typename V = T,
            std::enable_if_t<std::is_arithmetic_v<V>, bool> = false>
  auto test_pack(Args... args) {
    std::cout << "good" << std::endl;
    return 0;
  }
};
''')

# call from cling
cppyy.cppdef('''auto testing = TestSfinae<float>();''')
cppyy.cppdef('''auto single_call = testing.test_single(1);''')  # good
cppyy.cppdef('''auto pack_call = testing.test_pack(1,2,3);''')  # good

# call from bindings
testing = cppyy.gbl.TestSfinae['float']()
testing.test_single(1)  # good
testing.test_pack(1,2,3)  # fails

Which fails with the message

input_line_24:6:70: error: no matching member function for call to 'test_pack'
      new (ret) (int) (((TestSfinae<float>*)obj)->TestSfinae<float>::test_pack<int, int, int, float, false>(*(int*)args[0], *(int*)args[1],
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
input_line_18:11:8: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Args'
  auto test_pack(Args... args) {
       ^

Which (again, seems to me) has to do with cppyy explicitly providing the SFINAE template parameters somewhere in the process of passing the call down to its C++-binding.

@taehyounpark taehyounpark changed the title Template parameter pack + SFINAE not working Template class + SFINAE member function with variadic template arguments Nov 3, 2023
@wlav
Copy link
Owner

wlav commented Nov 3, 2023

That code that doesn't compile is generated in CallFunc (ie. ROOT/meta, a portion of which lives in cppyy-backend, yes, hence this problem also shows up in cppyy master). CallFunc reconstructs the function name (incl. template parameters) from the decl, not from any parameters provided by cppyy. Probably the code generator should check if a method is variadic and then not add the explicit template parameters.

Still recommended to report this for the ROOT repo. I'll probably fix it on my end b/c it affects cppyy proper, but per CERN rules, the ROOT team can not accept patches to ROOT code from me, so they'll have to come up with their own fix.

@taehyounpark
Copy link
Author

Thank you for the quick reply and insight!

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

No branches or pull requests

2 participants