给定T和函数名称和类型,我该如何解析T :: function?

时间:2012-08-10 18:18:31

标签: c++ templates member-function-pointers

给定一个Event结构和一个实现具有特定名称和原型的函数的对象,由Event结构知道,我想返回一个指针或绑定到该函数。究竟它返回的并不重要;它可以很容易地成为指向成员的函数或绑定。

这有点难以解释,所以这里有一些伪代码:

struct Foo {
    void onEvent();
};

struct Bar {
    void onEvent();
};

struct Event
{
    // I'm not sure what would go here
    // Needs something that can be used to resolve T::onEvent, without
    // knowing what T is until GetEventFunction is called.
    typedef std::function<void()> function_type;
};

template<typename T, typename EventType>
EventType::function_type GetEventFunction(T* object)
{
    return std::bind(T::(EventType::Something), object);
}

GetEventFunction<Foo, Event>(new Foo); // Returns Foo::onEvent
GetEventFunction<Bar, Event>(new Bar); // Returns Bar::onEvent

是否可以实现这种行为,或者C ++是否过于限制而不允许这样做?

请在回答之前阅读

我不是在寻找反思。据我所知,在编译时可以获得完成我目标所需的所有信息。

另外,我对替代方法不感兴趣。我知道很多方法可以通过其他代码实现此行为,例如每种事件类型的模板特化,但我正在寻找一种方法来实现这一目标。

2 个答案:

答案 0 :(得分:4)

  

也许我没有解释清楚,但每个Event类型的函数名称都是唯一的。 FooEvent应解决T::onFooEvent,而BarEvent应解决T::onBarEvent

C ++可以对类型和值进行操作,但不能对名称进行操作。这是处理文本,这是一个宏观层面的事情,发生在C ++正确看到代码之前。您不能使用BarEvent类型并将其转换为函数T::onBarEvent,因为它们之间没有关联,除了它们恰好是命名为

这就是Luc的答案使用特定名称的原因:函数名称必须是硬编码的。

现在,您可以通过使用特征模板来略微改变C ++的规则。例如,您可以创建一个event_traits模板类型,该模板类型具有成员函数,该函数需要T并在其上调用特定函数。它看起来像这样:

template<typename event_type>
struct event_traits
{
  template<typename T> void Dispatch(T *t) {t->DefaultEventFunction();}
};

以上使用DefaultEventFunction

如果您希望每个Event都有自己的事件函数,则需要为每个Event类提供专门化。如果您想强制执行此规则,则永远不要在任何DefaultEventFunction个对象中定义T;编译器会抱怨。将名称更改为不太可能使用的名称,例如WhyDidYouNameThisFunctionLikeThisStopIt

template<>
struct event_traits<FooEvent>
{
  template<typename T> void Dispatch(T *t) {t->onFooEvent();}
};

template<>
struct event_traits<BarEvent>
{
  template<typename T> void Dispatch(T *t) {t->onBarEvent();}
};

这是宏可以派上用场的地方:

#define REGISTER_EVENT_HANDLER(eventName)\
template<> struct event_traits<eventName>\
{\
  template<typename T> void Dispatch(T *t) {t->on ## eventName ();}\
};

因此,您的GetEventFunction将如下所示:

template<typename T, typename EventType>
EventType::function_type GetEventFunction(T* object)
{
    return std::bind(event_traits<EventType>::Dispatch<T>, object);
}

答案 1 :(得分:2)

如果你有成员的名称,那么你不需要知道一个类型 - 假设该成员不是一个重载的成员函数。

template<typename T>
auto GetEventFunction(T& object)
-> decltype( std::bind(&T::onEvent, std::ref(object)) )
{ return std::bind(&T::onEvent, std::ref(object)); }

// Usage:
Foo f;
auto event = GetEventFunction(f);

请注意,这有点人为,因为您提到的onEvent不带任何参数。如果是这样,你需要更多的脚手架。 (我建议写一个也接受一个对象的mem_fn,与std::mem_fn不同。)