简体   繁体   中英

Pass function pointer to template

I did have a situation very much akin to this:

#include <iostream>

template<class B>
class A
{
public:
    A<B>(const B& b) : m_b(b) {}
    void foo()
    {
        m_b(*this);
    }
private:
    B m_b;
};

class B
{
public:
    template<class C>
    void operator()(const C& c)
    {
        std::cout << "Bar!\n";
    }
};


int main()
{
    B b;        
    A<B> a(b);
    a.foo();

    return 0;
}

Then I decided to use a function pointer instead of the function object b, ie I wanted to do something like this:

#include <iostream>

template<class B>
class A
{
public:
    A<B>(const B& b) : m_b(b) {}
    void foo()
    {
        m_b(*this);
    }
private:
    B m_b;
};

template<class C>
void bar(const C& c)
{
std::cout << "Bar!\n";
}

int main()
{
    typedef void (*barPointer)(const A<barPointer>& a); // <--       
    A<barPointer> a(&bar);
    a.foo();

    return 0;
}

This obviously does not compile (notice the circularity at <--). My question is: how would one go about this?

I think the key question to ask is what is your barPointer type? It is a pointer-to-a-function, but as you've attempted to define it, you've created an infinitely recursive definition. To end the recursion, you have to consider what the "root" or "base-case" of this pointer type is. Since you know the type for the instance of A you will be passing to your function, then you really are looking for a "placeholder" type that will allow the template to be instantiated without the circularity. This could be a very "generic" function-pointer type like void(*)(void*) , or it could be something more specific, but in either case, I believe it needs to be a function pointer type that does not include the definition of A , but can be passed an A<> instance as its argument. The most generic form would be a void(*)(void*) , but you can always define some type of polymorphic base-class as well for greater type safety.

Here, for instance, would be an example of the most generic case:

typedef void (*generic_t)(void*);

template<typename T>
struct A
{
        A(const T& t): func_ptr(t) {}
        void foo() { func_ptr(this); }
        T func_ptr;
};

void func(void* arg)
{
        const A<generic_t>* a = reinterpret_cast<const A<generic_t>*>(arg);
}

int main()
{
        A<generic_t> a(&func);
        a.foo();
        return 0;
}

Although this looks dangerous, it's not really if you consider the fact that in your basePointer example you already knew the type of object you were going to pass to your basePointer function pointer. If you want more type-safety to prevent inadvertent mistakes, you could always create some type of abstract base class that A inherits from. I say "abstract Base class" because that would allow you to use the pointer passed to the function without an explicit cast to it's derived type. Then your "generic placeholder" function-ptr type could be something like void(*)(const Base&) rather than the non-type-safe void(*)(void*) .

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