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

Double argument pack expansion #450

Open
gostefan opened this issue Jan 10, 2025 · 0 comments
Open

Double argument pack expansion #450

gostefan opened this issue Jan 10, 2025 · 0 comments

Comments

@gostefan
Copy link

Channel

Is this a "C++Weekly" or "The [Fill in the Blank] Programmer" episode request?
I think it would fit an C++Weekly episode much better.

Topics

Advanced template parameter packs.

Length

I think it's more bite-sized to quickly show this advanced functionality.

Content

Motivation
I stumbled across the problem of converting JNI types to "normal" C++ types.
The goal was that there are the same classes in Java and C++ with the same interfaces etc for simple understanding.
There obviously has to be some JNI binding layer between Java and C++ to convert between the Java types and the C++ types.
With the hand full of classes and dozens of methods each, it's against DRY to have the same conversions in every interface call.
The goal was to come up with a call method with a template parameter pack such that that the class instance could be passed as first argument, a class member function as second parameter and then all the JNI arguments in the parameter pack like this:
call(instance, &MyClass::myMethod, arg1, arg2, arg3);

I don't think this is important to the content of the episode but explains why something like the following could be interesting at all.

Actual content
It's possible to unpack two parameter packs in parallel!
Here is an example of what I'm talking about. This a boiled down example of the example above (that doesn't make that much sense anymore).

#include <vector>

template<typename SRC, typename TGT>
TGT doConversion(SRC src);

template<>
int doConversion<double const&, int>(double const& arg) {
    return static_cast<int>(arg);
}

template<>
std::vector<int> const& doConversion<std::vector<int> const&, std::vector<int> const&>(std::vector<int> const& arg) {
    return arg;
}

template <typename TYPE, typename OUT, typename... FARGS, typename... ARGS>
OUT call(TYPE& obj, OUT (TYPE::*func)(FARGS...), ARGS const&... args) {
    return (obj.*func)(doConversion<ARGS const&, FARGS>(args)...);
}

class S {
  public:
    int getCount(int a, std::vector<int> const& b) {
        return 3 + b[0];
    }
};


int main() {
    S s;
    return call(s, &S::getCount, 3.0, std::vector<int>{3, 4});
}

My point is that inside call there is the line return (obj.*func)(doConversion<ARGS const&, FARGS>(args)...); which unpacks ARGS and FARGS simultaneously. I wasn't aware of this possibility - it even took me a while to understand how one template can have two parameter packs.

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

No branches or pull requests

1 participant