0

I'm trying to implement my own function object class and bind function (only need to wrap member functions of 2 parameters). I'm restricted to use GCC 4.4.6 and c++0x is not an option.

My Code is as follows. It wouldn't compile.

#pragma once

namespace utils
{

template<class>
class CFunction;

template<class TRet, class Arg1, class Arg2>
class CFunction<TRet(Arg1, Arg2)>
{
public:
    typedef TRet (*FuncPtr) (void*, Arg1, Arg2);
    void* m_pObj;
    FuncPtr m_FuncPtr;

    TRet operator()(Arg1 arg1, Arg2 arg2)
    {
        return m_FuncPtr(arg1, arg2);
    }

    template <class TObj, TRet (TObj::*TMemFunc)(Arg1, Arg2)>
    static CFunction Create(TObj* pObj)
    {
        CFunction Ret;
        Ret.m_pObj = (void*)pObj;
        Ret.m_FuncPtr = &Caller<TObj, TMemFunc>;
        return Ret;
    }
private:
    template<class TObj, TRet (TObj::*TMemFunc)(Arg1, Arg2)>
    static TRet Caller(void* obj, Arg1 arg1, Arg2 arg2)
    {
        TObj* pObj = static_cast<TObj*>(obj);
        return (pObj->*TMemFunc)(arg1, arg2);
    }
};


template<class TRet, class TClass, class Arg1, class Arg2>
CFunction<TRet(Arg1, Arg2)> Bind(TRet (TClass::*func)(Arg1, Arg2), TClass *pObj)
{
    return CFunction<TRet(Arg1, Arg2)>::Create<TClass, func>();
}

} // end of namespace utils

The compile reports

Functional.h: In function ‘utils::CFunction<TRet(Arg1, Arg2)> utils::Bind(TRet (TClass::*)(Arg1, Arg2), TClass*)’:
Functional.h:48: error: expected primary-expression before ‘,’ token
Functional.h:48: error: expected primary-expression before ‘)’ token

Would anyone tell me what's wrong with the code and how to make it work


After fixing the problem @Vittorio and @MSAlters metioned. I got new Compile errors.

Fixed Code

#include <iostream>

namespace utils
{

template<class>
class CFunction;

template<class TRet, class Arg1, class Arg2>
class CFunction<TRet(Arg1, Arg2)>
{
public:
    typedef TRet (*FuncPtr) (void*, Arg1, Arg2);
    void* m_pObj;
    FuncPtr m_FuncPtr;

    TRet operator()(Arg1 arg1, Arg2 arg2)
    {
        return m_FuncPtr(m_pObj, arg1, arg2);
    }

    template <class TObj, TRet (TObj::*TMemFunc)(Arg1, Arg2)>
    static CFunction Create(TObj* pObj)
    {
        CFunction Ret;
        Ret.m_pObj = (void*)pObj;
        Ret.m_FuncPtr = &Caller<TObj, TMemFunc>;
        return Ret;
    }
private:
    template<class TObj, TRet (TObj::*TMemFunc)(Arg1, Arg2)>
    static TRet Caller(void* obj, Arg1 arg1, Arg2 arg2)
    {
        TObj* pObj = static_cast<TObj*>(obj);
        return (pObj->*TMemFunc)(arg1, arg2);
    }
};


template<class TRet, class TClass, class Arg1, class Arg2>
CFunction<TRet(Arg1, Arg2)> Bind(TRet (TClass::*func)(Arg1, Arg2), TClass *pObj)
{
    return CFunction<TRet(Arg1, Arg2)>::template Create<TClass, func>(pObj);
}

} // end of namespace utils

class TestLogic
{
public:
  bool Test(std::string& str, double d) {
     std::cout << str << ",  " << d << std::endl;
     return true;
  }
};

int main(int argc, const char **argv) {
    TestLogic testObj;
    utils::CFunction<bool(std::string&, double)> f = utils::Bind(&TestLogic::Test, &testObj);
    std::string str("hello");
    f(str, -1.0);
}

New Error:

prog.cc: In function 'utils::CFunction<TRet(Arg1, Arg2)> utils::Bind(TRet (TClass::*)(Arg1, Arg2), TClass*) [with TRet = bool, TClass = TestLogic, Arg1 = std::string&, Arg2 = double]':
prog.cc:59:   instantiated from here
prog.cc:43: error: 'func' is not a valid template argument for type 'bool (TestLogic::*)(std::string&, double)'
prog.cc:43: error: it must be a pointer-to-member of the form `&X::Y'
prog.cc:43: error: no matching function for call to 'utils::CFunction<bool(std::string&, double)>::Create(TestLogic*&)'

Can anyone help me with this pls?

You can run this code enter link description here

1 Answers1

3

You need to use the template keyword as a disambiguator in Bind:

return CFunction<TRet(Arg1, Arg2)>::template Create<TClass, func>();
//                                  ^~~~~~~~

This is because Create is a dependent name, and the compiler doesn't know if you're trying to call a template function or compare it with TClass. More reading on the subject: Where and why do I have to put the "template" and "typename" keywords?

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • Also, `Create` takes a single `TObj*`, but it's called with an empty argument list. Because the name lookup fails, this error isn't yet spotted. – MSalters May 16 '19 at 13:35
  • @MSalters Yes. I encountered this after fixing the name lookup problem memtioned by Vittorio. But my code still not compile. I modified the question. Would you pls hlep me solve this? Thanks a lot – Feiyu Chen May 16 '19 at 15:20
  • Luckily that one is trivial. You're using a runtime variable `func` as a compile-time argument `Create`. That's not how C++ works. I suggest you look at an older Boost version (pre C++11, so 1.46 or similar). The C++11 `bind` came from Boost. – MSalters May 16 '19 at 15:35
  • @MSalters Allright. I actually tried to read Boost bind version last night. But stopped right after begnning. Template is realy a monster to me. Guess I have to pick it up again. v_v. Again, thank you very much ! – Feiyu Chen May 16 '19 at 15:43
  • @FeiyuChen: It is a monster. Which is why you want it; otherwise you need to invent that yourself. C++11 was not a random fluke; it was designed to make Boost and similar libraries easier to write. – MSalters May 16 '19 at 15:46