4
votes

I have a class which has a variadic member function:

class class_name {
  template<ArgTypes.. args>
  some_return_type memberMethod(ArgTypes... args) {
    //stuff...
  }
}

I need to force instantiation of this method inside the class definition block. I loose the method name outside of the class definition block because the class is generated by a bunch of macros.

I try to force the instantiation by copying a pointer to a specialised member function (pseudo code):

template<typename Self, typename RetType, typename... ArgTypes>
struct force_instantation_imlp<Self, RetType, type_placeholder, type_placeholder<ArgTypes...>> {
    force_instantation_imlp() {
        using instate = RetType (Self::*)(ArgTypes...);
        instate force = &Self::memberMethod<ArgTypes...>;        
    }
};


class class_name {
  template<ArgTypes.. args>
  some_return_type memberMethod(ArgTypes... args) {
    //stuff...
  }

  force_instantation_imlp<class_name, some_return_type, rest_of_types_deduced_from_context> force_virtual_instantation;
}

type_placeholder is just a helper template to "freeze" parameter pack.

This unfortunately gives me a compile error

error: expected primary-expression before ‘...’ token instate force = &Self::memberMethod<ArgTypes...>;

I guess that this error results from teh fact that the member function is a variadic template.

Is there any way to force variadic template member function instantiation inside the class definition block?

1
You could just use auto instead of instate : auto force = &Self::memberMethod<ArgTypes...>;. That saves you from writing the using to define a type. - Nawaz
Have you tried leaving out the explicit template arguments in instate force = &Self::memberMethod<ArgTypes...>;? - dyp
@Nawaz good point. I still didn't develop c++11 habits. Still the issue remains open. - Marcin
... I think you're missing a template: &Self::template memberMethod<ArgTypes...>; - dyp
@Marcin The reason why instate force = &Self::memberMethod; works is that the compiler can select the overload based on the required type (type of instate) in that context. That of course isn't possible for decltype. So inside decltype you'd need either a cast or explicitly specify the overload (e.g. using explicit template arguments). This of course is useless as you could directly specify the function type w/o decltype if you can access those parameter types. - dyp

1 Answers

2
votes

(Repeating from my comments to the OP.)

The actual problem in the line instate force = &Self::memberMethod<ArgTypes...>; is a missing template keyword:

instate force = &Self::template memberMethod<ArgTypes...>;

See, e.g. Where and why do I have to put the “template” and “typename” keywords?

Actually, the explicit template arguments are not necessary here [over.over]/1:

A use of an overloaded function name without arguments is resolved in certain contexts to [...] a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context.

i.e., because instate defines the function type, the compiler is able to determine which overload (here: template specialization) to choose for the name Self::memberMethod.


There might be easier solutions to force instantiation of a function template, even inside the class definition. One that comes to my mind is to use a private typedef like using dummy = integral_constant<instate, &Self::memberMethod>; (or a static constexpr instate dummy = &Self::memberMethod;).

I'm quite, but not 100 % sure the typedef forces the instantiation of the member function template. The function template is instantiated when a definition of that function is required, and the ODR suggests this is the case here: "A function whose name appears as a potentially-evaluated expression is odr-used if it is the unique lookup result or the selected member of a set of overloaded functions" and "Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program"