0

I'm new to c++ templates so bear with me.

What I want to do is implement some sort of strategy pattern in my class, by making use of templated functions. I assume this would inline the strategies.

My understanding is that this can be achieved with functors, but I don't want to introduce new classes, I just want inlined strategy functions in my class.

Lets say I have a class Calculator.

Calculator.h

#ifndef CALCULATOR_H
#define CALCULATOR_H


class Calculator
{
    public:
        Calculator();
        virtual ~Calculator();
        typedef void (*Strategy)(int param1, int param2);

        void add(int param1, int param2);

        template<class T>
        void doStrategy(T strategy, int param1, int param2);
    protected:
    private:
};

#endif

Calculator.cpp

Calculator::Calculator()
{
    //ctor
}

Calculator::~Calculator()
{
    //dtor
}

void
Calculator::add(int param1, int param2)
{
    std::cout << "Sum " << param1+param2 << std::endl;
}

template<class T>
void
Calculator::doStrategy(T strategy, int param1, int param2)
{
    strategy(param1,param2);
}

main.cpp

int main()
{
    Calculator calc = Calculator();

    calc.doStrategy<Calulator::Strategy>(calc.add,2,3);
    return 0;
}

This fails with

error: no matching function for call to ‘Calculator::doStrategy(<unresolved overloaded function type>, int, int)’|
note: candidate is:|
note: template<class T> void Calculator::doStrategy(T, int, int)|
note:   template argument deduction/substitution failed:|
note:   cannot convert ‘calc.Calculator::add’ (type ‘<unresolved overloaded function type>’) to type ‘void (*)(int, int)’|

== Later edit ==

main.cpp

typedef void (Calculator::*Strategy)(int, int);
int main()
{
    Calculator calc = Calculator();
    Strategy strategy = &Calculator::add;

    calc.doStrategy<Strategy>(strategy,2,3);
    return 0;
}

Still fails with:

undefined reference to `void Calculator::doStrategy<void (Calculator::*)(int, int)>(void (Calculator::*)(int, int), int, int)'
farnsworth
  • 349
  • 3
  • 13
  • Look at this link for the cause of your latest error: http://www.parashift.com/c++-faq/separate-template-fn-defn-from-decl.html – JaredC Jan 06 '13 at 04:25

2 Answers2

5

void add(int param1, int param2) is not a static method, thus it is called on an instance of an object.

This means that it can't be casted to typedef void (*Strategy)(int param1, int param2) which is a method that takes 2 integers and returns nothing because the former add has an implicit this which is hidden in code but exists in reality. Actually the signature of the method is void (Calculator::*)(int,int). Just set the method to static and it should be fine.

I suggest you to read how pointer to member functions work in detail here, but since you are working in C++ I really suggest you to take advantage of functors.

Jack
  • 131,802
  • 30
  • 241
  • 343
  • static is not an option, the real world example of what I'm trying to do is more complicated than this, but can't be posted here. – farnsworth Jan 06 '13 at 03:06
  • 2
    Then read the link I posted to find all the details required to work with pinter to member functions but I keep saying that using functors would relieve much pain even if you will end up having a more verbose solution. – Jack Jan 06 '13 at 03:08
  • +1 for functors: http://stackoverflow.com/questions/356950/c-functors-and-their-uses If you are using C++11, you should also consider to use lambda expressions. – Philipp Claßen Jan 06 '13 at 03:12
  • No I'm not using C++11 and functors are overhead on the low power embedded device I'm working with. – farnsworth Jan 06 '13 at 03:14
  • 1
    The overhead of a functor is basically a virtual invocation, since you already have an indirect call even with a function pointer I don't really think it could make a difference unless you are calling them millions of times per second. – Jack Jan 06 '13 at 03:17
  • @Jack: If the member function pointer is a compile time constant, it may not require runtime indirection. – Ben Voigt Jan 06 '13 at 04:20
0

my english is short... just remain code...

in calculator.h

// this template function use only for calculator's method
// and method must have two arguments.
template<typename Method>
void doStrategy(Method strategy, int param1, int param2)
{
    // argument strategy MUST BE calculator's member function pointer,
    // member function pointer need object, not class
    (this->*strategy)(param1, param2);
}

in main.cpp

Calculator cal;

cal.doStrategy(&calculator::add, 2, 3);

.. more generally...

in calculator.h

// this template function do not use only for calculator's method
// but method must have two arguments.
template<typename Class, typename Method>
void doStrategy(Class* pObject, Method strategy, int param1, int param2)
{
    // argument strategy MUST BE Class's member function pointer,
    // member function pointer need object, not class
    (pObject->*strategy)(param1, param2);
}

in main.cpp

// definition of another member function...
struct foo
{
    void bar(int param1, param2)
    {
        std::cout << "foo::bar " << param1 - param2 << std::endl;
    }
};

int main()
{
    Calculator cal;
    foo test;

    cal.doStrategy(&cal, &calculator::add, 2, 3);
    cal.doStrategy(&test, &foo::bar, 2, 3);

    foo* just_for_member_function = NULL;

    cal.doStrategy(just_for_member_function, &foo::bar, 5, 1); 

    return 0;
}

more generally?

um next time...

jklim
  • 21
  • 3