简体   繁体   中英

Avoiding explicit functor template type

I'm playing with functors. I'm using the standard example below:

class C {
public:
    template <typename Func>
    void foo(Func fun)
    {
        fun();
    }
};

struct S {
    void operator()() { printf ("in S\n"); }
};
....
C myClass;
myClass.foo (S());

This works nicely and I don't need to explicitly provide the S template type in the call to foo(), it just figures it out. But suppose I want to store the functor as a member variable and call it later:

class C {
public:
    template <typename Func>
    void foo(Func fun) {
        _myFunc = fun;
    }

    void someOtherThing() { 
        _myFunc();
    }
private:
    WHAT_IS_THIS_TYPE _myFunc;
};

Do I now need to make the whole class a template? If so, can the compiler infer the template type as it did with the single functor, or must I provide it explicitly? Thanks.

You can use std::function (in C++11) or boost::function to store callable objects (functions, functors). It implements type erasure pattern.

class C {
public:
  template <typename Func>
  void foo(Func fun) {
    _myFunc = fun;
  }

  void someOtherThing() { 
    _myFunc();
  }
private:

  std::function<void()> _myFunc;
};

Here's a hand-made way to avoid making class C a template:

struct C {
    template <typename Func>
    void foo(Func fun) {
        _myFunc = static_cast <void*>(&fun);
        stub = call <Func>;
    }

    void someOtherThing() {
        stub(_myFunc);
    }

private:
    void* _myFunc;
    void (*stub)(void*);

    template <typename F>
    static void call(void* f) {
        (*static_cast <F*>(f))();
    }
};

struct S {
    void operator()() { std::cout << "in S" << std::endl; }
};

int main()
{
    S s;
    C myClass;
    myClass.foo(s);
    myClass.someOtherThing();
}

When you call foo() , type Func is "stored" inside the template static function call , a pointer to (an instatiation of) which is stored in stub . The latter is called by someOtherThing to actually invoke _myFunc , which is nothing but plain void* . For this to happen, _myFunc is first cast back to the correct type, which is only known inside call 's body.

The only catch is that using pointers to functions there can be no inlining for stub(...) call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM