cxxl
cxxl

Reputation: 5399

Pointer-to-member as template argument

I use Visual C++ 2012. I want to parameterize a template function with a pointer to another function. It all works nicely outside of a class:

int add(int a, int b) {
   return a + b;
}
typedef int (*func)(int a, int b);
template<func F> int do_it(int a, int b) {
   return F(a, b);
}
int foo(int a, int b) {
   return do_it<add>(a, b);
}

Visual C++ 2012 compiles and optimizes that perfectly.

Now, I put it inside a class and adjust it for pointer-to-member:

struct S {
   int add(int a, int b) {
      return a + b;
   }
   typedef int (S::*func)(int a, int b);
   template<func F> int do_it(int a, int b) {
      return F(a, b);     // <-- here be error!
   }
   int foo(int a, int b) {
      return do_it<&S::add>(a, b);
   }
};
S s;

int bar(int a, int b) {
   return s.foo(a, b);
}

But that gives me a compiler-error:

Microsoft (R) C/C++ Optimizing Compiler Version 17.00.51106.1 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

x2.cpp
x2.cpp(7) : error C2064: term does not evaluate to a function taking 2 arguments
        x2.cpp(10) : see reference to function template instantiation 'int S::do_it<int S::add(int,int)>(int,int)' being compiled

Any idea why and how to fix it?

Upvotes: 2

Views: 503

Answers (5)

reder
reder

Reputation: 1108

One point further: write your "do_it" more generally as

template<class F> int do_it(F f, int a, int b) {
   return f(a, b);        }

Now, you can pass it any function of two integers:

int mul(int a, int b) { return a*b ; }
S s;
s.do_it(mul,2,3);

When you intend to use it inside your class with a member function, just bind it with this. Using boost::bind,

   int foo(int a, int b) {
       return do_it( boost::bind(&S::add,this,_1,_2),a,b)  ;

Upvotes: 0

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154015

You need to provide the object when calling a pointer-to-meber function:

(this->*F)(a, b);

Upvotes: 1

Mike Seymour
Mike Seymour

Reputation: 254701

Member-function pointers must be called on an object; unlike a normal member function call, this must be specified explicitly:

(this->*F)(a,b);

Although, if the function doesn't need to access this, perhaps it should be static (or a non-member), specified by a normal function pointer.

Upvotes: 2

Jesse Good
Jesse Good

Reputation: 52365

It looks like you just need to call the member function pointer on an object:

template<func F> int do_it(int a, int b) {
      return (this->*F)(a, b);
}

Pointers to members always need to be called on an object, unlike free and static member functions, which is why you need the above syntax.

Upvotes: 1

Nbr44
Nbr44

Reputation: 2062

The syntax for pointers to members still apply. You should write :

typedef int (S::*func)(int a, int b);
   template<func F> int do_it(int a, int b) {
      return (this->*F)(a, b);
   }

Using a pointer to member always require associating an object with it - here, it makes sense you would call your pointer on this.

Upvotes: 4

Related Questions