Type of the first parameter of a member function in C++11
Asked Answered
S

1

8

I have written a metafunction to retrieve the type of the first parameter of a member function, which of course receives one or more parameters. The code I have written is as follow:

template <typename...> struct parameter;

template < typename O, typename A, typename R, typename... Args>
struct parameter <R (O::*)(A, Args...)  > {
     using first_param = A;
};

I use this meta function as follow:

using mem_fn = void(mem_type::*)(std::vector<int>);
using f_pm = parameter<mem_fn>::first_param;

and it compiles and works. But when I have a class:

struct mem_type{

    void update(std::vector<int>) {

    }
};

and use my metafunction as follow:

using mem_fn = decltype(mem_type::update);
using f_pm = parameter<mem_fn>::first_param;

the code does not compiles and visual studio 2013 gives: error C2027: use of undefined type parameter<mem_fn>.

Does anyone knows the reason for this error?

Skiffle answered 26/11, 2014 at 21:28 Comment(5)
Does using mem_fn = decltype(&mem_type::update); work? I've seen similar issues in the past and being more explicit on the address has helped. Here to match your member function pointer specialisation.Didi
MSVC using support is flaky. Try typedef? Oh, and &mem_type::update might also help. Bah, @Didi beat me to the 2nd one. mem_type::update isn't a valid way to get a pointer to it: unlike functions, member functions to not auto-decay the same way.Bush
Your specialization matches a pointer-to-member-function, so decltype(&mem_type::update).Marelya
@Snps No it doesn't.Marelya
It works fine here using g++ (Debian 4.7.2-5) 4.7.2 (if you supply the ampersand decltype(&mem_type::update). I suspect VS2013 could be flaky with the use of usingMyrmecophagous
M
4

First, an id-expression naming a nonstatic member function (mem_type::update in this case) can't be used as an unevaluated operand (such as the operand of decltype). §5.1.1 [expr.prim.general]/p13 (footnote omitted):

An id-expression that denotes a non-static data member or non-static member function of a class can only be used:

  • as part of a class member access (5.2.5) in which the object expression refers to the member’s class or a class derived from that class, or
  • to form a pointer to member (5.3.1), or
  • if that id-expression denotes a non-static data member and it appears in an unevaluated operand.

§7.1.6.2 [dcl.type.simple]/p4:

The operand of the decltype specifier is an unevaluated operand (Clause 5).

And even if update were a regular function, decltype would produce a function type rather than a function pointer type, and your specialization matches a pointer-to-member-function type.

You need to created a pointer-to-member-function with & - i.e., decltype(&mem_type::update).

Marelya answered 26/11, 2014 at 22:39 Comment(3)
Exactly (nice answer)Myrmecophagous
Good answer. Is there a better way to accomplish the task of getting the first parameter of a member function?Skiffle
@RaulAlonso You actually need 11 extra specializations (in addition to the one you have) to handle the various combinations of cv- and ref-qualifiers, but I'm not aware of any other way to do it. Also, the base template parameter shouldn't be variadic.Marelya

© 2022 - 2024 — McMap. All rights reserved.