Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointers to member as variadic template parameters

Is it possible to pass pointers-to-member as variadic template arguments. I can't seem to figure out the syntax.

for a function call it works like this:

struct A
{
    int a;
    float b;
}

template <typename ... TArgs> void f(A *obj, TArgs ... params)
{
    void *members[] { (&(obj->*params))... };
    // ... do something ...
}

That can be used like this:

f(obj, &A::a, &A::b);

I would like to pass params in a similar fashion to a class template

template <[something] ... params> class Foo
{
    void Bar(A *obj)
    {
        void *members[] { (&(obj->*params))... };
        // ... do something ...
    }
};

That should be used like this:

Foo<&A::a, &A::b> foo;
foo.bar(obj);

I'm having trouble figuring out what [something] should be.

If member type is known and there is only one parameter, it can be done like this:

template <int A::*ptr> //...

Is there a way to generalize this for variadic parameter list of member pointers where members are of different unknown beforehand types?

Update: Variadic argument pack for member pointers of fixed known types is declared like so:

template<int A::*...ptr> struct Foo {};

Now I just need to replace int with typename that can be deduced.

And with C++17, following works perfectly:

template<auto A::*...ptr> struct Foo {};

Unfortunately I need a solution that will work with C++14

like image 503
Ghostrider Avatar asked May 19 '17 18:05

Ghostrider


1 Answers

In C++14, you can use another level of indirection to do that:

struct A {
    int a;
    float b;
};

template<typename... T>
struct Bar {
    template <T A::*... params>
    struct Foo {
        void Bar(A *obj) {
            void *members[] { (&(obj->*params))... };
            // ... do something ...
            (void)members;
        }
    };
};

int main() {
    A a;

    Bar<int, float>::Foo<&A::a, &A::b> foo;
    foo.Bar(&a);
}

auto keyword (introduced with the C++17 for non-type template parameters, as you mentioned) solves more or less this kind of issues. Think of std::integral_constant and how would it be more user-friendly if you hadn't to specify each time the type as the first argument...

like image 63
skypjack Avatar answered Oct 25 '22 20:10

skypjack