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

发布于 2024-10-07 02:43:30 字数 474 浏览 3 评论 0原文

我有一个像这样的调用者函数:

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

I have a caller function like this:

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

and while this works perfectly:

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

this code does not compile with error on the second line:

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

Is there any way to fix it? I need the CallMethod template to take a constant pointer to a method that is stored in a variable.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

许仙没带伞 2024-10-14 02:43:30

所有模板参数必须在编译时已知。因此,如果 method 实际上是一个变量而不是特定的函数,则无法执行您想要的操作。

相反,您可以创建一个模板结构,它具有指向成员函数的指针作为成员,并实现一个operator(),其行为类似于CallMethodA、方法>

All template parameters must be known at compile time. So if method is really a variable and not a particular function, there is no way to do what you want.

Instead, you may be able to make a template struct which has a pointer to member function as a member and implements an operator() which acts similarly to CallMethod<A, method>.

尽揽少女心 2024-10-14 02:43:30

此时,我已经确定您有一个需要函数和指针的 API,并且您需要提供这样的 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;
}

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

如果您控制着“另一侧”,那么不要按照设计这样做,而是让该侧保留 boost::function 并调用它。

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

At this point I have ascertained that you have an API that takes a function and a pointer and you need to supply it such. I assume that you must always supply it an A* pointer?

If it is a very generic callback but must be a function (can't be a boost::function) and must be a pointer (possibly void*) then you need a function a bit like this:

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

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

As in this case I am calling delete at call time, so I have assume we call new at invoke time, i.e. when you build up your pointer on which your call is made. Of course it might not be that your pointer you pass is deleted on first call, so manage the lifetime appropriately.

If you are in control of the "other side" then don't do this by design but let that side hold the boost::function and just call it.

Memory management can still be an issue you need to take care of. For example, when you call boost::bind it wraps things in a struct behind the scenes for you. If these are pointers you allocated with new you need to delete them at sometime. If they are references they must still be valid at the point of call. pointers to local variables can also be a problem. shared_ptrs are ideal, of course. And the bug tracking to the boost::bind error is very very hard to find if you use that concept a lot.

送君千里 2024-10-14 02:43:30

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

标头:

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,则为智能指针),您可以循环遍历该向量并使用它来执行各种与子类相关的操作。

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

更新:鉴于您需要一个普通的 C 函数指针,有一些技巧可能会影响 c++0x 或 boost 中的运行时性能:bindfunction: :target 等等...

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

It looks like you're trying to implement an interface via templates. It might be possible, but wouldn't it be nicer to have a base class with a virtual function, and use a base class pointer to access the virtual function via a simple function call?

Header:

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

Source file:

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

Example usage:

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

You can store a vector of pointers (or smart pointers if you use boost or C++0x) which you can loop through and use this to do all kinds of SubClass dependent stuff.

Alternatively, use boost::function or std::function (C++0x) which is an object containing the member function in question and pass that as a template parameter, using the object instance as a first argument. Which comes down to a workaround of the above.

UPDATE: Seeing that you need a plain C function pointer, there are some tricks that might imapct runtime performance in c++0x or boost: bind, function::target and so forth...

You will need this to get a function pointer out of a std/boost::function, and this to bind the first argument to an object. bind acts at runtime, so maybe a template would be better in this case...

陌上芳菲 2024-10-14 02:43:30

首先,请创建 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)()>;

First, please create typedefs http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.5

Second,

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

In this case, method is a variable and variables can not be template arguments. I haven't tested it but perhaps you could try...

void (*function)(A *) = &CallMethod<A, void (A::*method)()>;
盛夏尉蓝 2024-10-14 02:43:30

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

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

What if 2 methods have the exact same signature ?

The template can not distinguish on it (it selects on type, not value) and thus the same generated template function will call the first method or the second, would you bet your hand on it ?

You can use some tricks to make a different type at compile time, using the __LINE__ macro, but it involves mixing macro with current code which will be hard to follow.
This code:

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

However you'll not be able to save the pointer to a method in a variable and make a "auto wrapper" from it. It's now runtime, you need a runtime solution for this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文