繁体   English   中英

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

[英]C++ passing method pointer as template argument

我有这样的调用函数:

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模板来获取一个指向存储在变量中的方法的常量指针。

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

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

在这一点上,我已经确定你有一个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错误的错误。

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

标题:

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),它是包含所讨论的成员函数的对象,并使用对象实例作为第一个参数将其作为模板参数传递。 这归结为上述的解决方法。

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

你需要这个来从std/boost::function获取一个函数指针,这将把第一个参数绑定到一个对象 bind在运行时动作,所以在这种情况下,模板可能更好......

如果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);

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

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

第二,

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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