C ++传递方法指针作为模板参数

时间:2010-12-08 13:28:34

标签: c++ templates pointers methods

我有这样的来电功能:

template<typename T, void (T::*method)()>
void CallMethod(T *object){
    (object->*method)(args);
}

虽然这很有效:

void (*function)(A *) = &CallMethod<A, &A::method>;

这段代码在第二行没有编译错误:

void (A::*method)() = &A::method;
void (*function)(A *) = &CallMethod<A, method>;

有什么办法可以解决吗?我需要CallMethod模板来获取一个指向存储在变量中的方法的常量指针。

5 个答案:

答案 0 :(得分:2)

所有模板参数必须在编译时知道。因此,如果method实际上是一个变量而不是一个特定的函数,那么就没有办法做你想做的事。

相反,您可以创建一个template struct,其中有一个指向成员函数的指针作为成员,并实现operator(),其作用与CallMethod<A, method>类似。

答案 1 :(得分:2)

此时我已经确定你有一个带有函数和指针的API,你需要提供它。我假设你必须总是提供一个A *指针?

如果它是一个非常通用的回调但必须是一个函数(不能是boost :: function)并且必须是一个指针(可能是void *)那么你需要一个像这样的函数:

struct GenericHolder
{
   boost::function0<void> func;
};

void GenericCallback( void * p )
{
   GenericHolder * holder = static_cast< GenericHolder * >(p);
   holder->func();
   delete holder;
}

在这种情况下,我在调用时调用delete,所以我假设我们在调用时调用new,即当你构建指针时调用它。当然,可能不是您传递的指针在第一次调用时被删除,因此适当地管理生命周期。

如果你控制“另一面”,那么不要按设计做到这一点,但让那边持有boost :: function并调用它。

内存管理仍然是您需要处理的问题。例如,当你调用boost :: bind时,它会为你在幕后的结构中包装东西。如果这些是你用new分配的指针,你需要在某个时候删除它们。如果它们是引用,它们必须在通话时仍然有效。指向局部变量的指针也可能是个问题。 shared_ptrs当然是理想的。如果您经常使用该概念,那么很难找到跟踪boost :: bind错误的错误。

答案 2 :(得分:1)

看起来您正在尝试通过模板实现接口。有可能,但是拥有一个带虚函数的基类并使用基类指针通过一个简单的函数调用来访问虚函数会不会更好?

部首:

class AbstractBase
{
public:
    virtual void func() = 0;
}
class SubClass : public AbstractBase
{
public:
    void func();
}

源文件:

void SubClass::func()
{
    std::cout << "Virtual function called.\n";
}

使用示例:

int main()
{
    AbstractBase* base;
    base = new SubClass();
    base->func(); // virtual function call through base pointer will use SubClass's implementation
    return 0;
}

您可以存储一个指针向量(如果使用boost或C ++ 0x,则为智能指针),您可以循环使用它来执行各种SubClass相关的操作。

或者,使用boost::functionstd::function(C ++ 0x),它是包含相关成员函数的对象,并将其作为模板参数传递,使用对象实例作为第一个参数。这归结为上述的解决方法。

UPDATE :看到你需要一个简单的C函数指针,有一些技巧可能会影响c ++ 0x或boost中的运行时性能:bindfunction::target等等...

您需要this to get a function pointer out of a std/boost::functionthis to bind the first argument to an objectbind在运行时起作用,因此在这种情况下,模板可能会更好......

答案 3 :(得分:0)

首先,请创建typedef http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5

第二,

void (*function)(A *) = &CallMethod<A, method>;

在这种情况下,方法是一个变量,变量不能是模板参数。我没有测试过,但也许你可以试试......

void (*function)(A *) = &CallMethod<A, void (A::*method)()>;

答案 4 :(得分:0)

如果2种方法具有完全相同的签名怎么办?

模板无法区分它(它选择类型,而不是值),因此相同的生成模板函数将调用第一种方法或第二种方法,你会打赌它吗?

您可以使用一些技巧在编译时使用 __ LINE __ 宏制作不同的类型,但它涉及将宏与当前代码混合,这很难遵循。 这段代码:

template<typename T, void (T::*method)(), int>
void CallMethod(T *) { ... }
#define MakeCallMethod(X, Y) &CallMethod<X, X::&Y, __LINE__>

// This will work (it does not without the __LINE__ trick, ptr1 == ptr2 in that case)
typedef void (*ptrFunc)(A *);
ptrFunc ptr1 = MakeCallMethod(A, method);
ptrFunc ptr2 = MakeCallMethod(A, otherMethodWithSameSignature);

Assert(ptr1 != ptr2);

但是,您无法将指针保存到变量中的方法并创建一个&#34;自动包装器&#34;从中。它现在是运行时,你需要一个运行时解决方案。