skypjack
skypjack

Reputation: 50540

Template variadic argument referenced from another argument

I'm in trouble for the way I should reference arguments in a template (honestly, I strongly suspect that it's not possible to achieve what I'd like to do).

It follows an example of what I'd like to do (of course, this is not syntactically legal, the aim is to give the idea of which is the target):

template<class C, Ret(C::*Member)(Params...), typename Ret, typename... Params>
class MyClass { }

In other terms, I'd like to reference a member of a class, by specifying at the same time also which is the returned value and the parameters of that method.

Unfortunately, the only way I see to do that is something like the following one (well, it depends indeed on where those typenames are required, anyway it may be a meaningful example):

template<typename Ret, typename... Params>
class MyClass {
public:
    template<class C, Ret(C::*Member)(Params...)>
    MyClass(C *c) { /* do something else and give sense to this class */ }
}

Besides the one above, that is to break the interlacing by introducing a templated constructor, there exists another valid approach to obtain the same result with the sole class template signature?

I know (pretty simple) how to achieve that in case of not variadic template (as an example, move Ret before Member), but the variadic one (Params) has to lay at the end of the template list and I cannot refer it in any way.

Upvotes: 3

Views: 117

Answers (1)

skypjack
skypjack

Reputation: 50540

According with this question, a viable solution could be to rely on deduction forced by a default value.

As an example, the following code should be valid:

class MyClass {
public:
    template <class C, typename R, typename... P, R(C::*M)(P...) = &C::foo>
    void bar(C *c) { }
};

I cite part of the linked question (a citation that is a citation for itself, I'm in a loop):

A template parameter pack of a function template shall not be followed by another template parameter unless that template parameter can be deduced from the parameter-type-list of the function template or has a default argument.

Because of that, the following code should not be allowed instead, even if it compiles with GCC:

class MyClass {
public:
    template <class C, typename R, typename... P, R(C::*M)(P...)>
    void bar(C *c) { }
};

Well, quite tricky, not so flexible a solution and honestly I ended up far ago with a bit of refactoring, but for the sake of clarity I've decided to add an answer and close the question with a snippet that compiles.

Upvotes: 2

Related Questions