指向函数的模板指针的部分模板特化
partial template specialization for template pointer to function
考虑以下摘要 Subscription
class:
template <typename TMessage>
class Subscription {
public:
virtual ~Subscription() {}
virtual bool handle(const TMessage &) = 0;
};
在某些情况下,如果一个 class 可以单独实现此抽象 class 多次 可能会很方便 - 即使是相同的 TMessage
- 和不强制继承。
为了实现这一点,我使用模板指针按以下方式运行:
template <typename TMessage, typename TCaller, bool(TCaller::*TMethod)(const TMessage &)>
class Invoker : public Subscription<TMessage> {
public:
Invoker(TCaller *caller) :
m_caller(*caller) {
}
virtual bool handle(const TMessage &message) {
return (m_caller.*TMethod)(message);
}
protected:
TCaller &m_caller;
};
这允许创建抽象 class 的模板生成实现,如下所示:
(而不是在几个不同的 classes 中实现并在它们之间共享对象):
struct MyMessage {};
class Logic {
public:
Logic() :
m_subscription1(new Invoker<MyMessage, Logic, &Logic::handleSubscription1>(this)),
m_subscription2(new Invoker<MyMessage, Logic, &Logic::handleSubscription2>(this)) {
}
~Logic() {
delete m_subscription1;
delete m_subscription2;
}
bool handleSubscription1(const MyMessage &message) {
// handle message... uses class members
return true;
}
bool handleSubscription2(const MyMessage &message) {
// handle message... uses class members
return false;
}
private:
Subscription<MyMessage> *m_subscription1;
Subscription<MyMessage> *m_subscription2;
};
问题是,我想让用户模块(即 Logic
class)实现 void
句柄函数以及 bool
选项。
现在,我当然可以创建 2 个不同的 Invoker
classes - 一个像上面的代码一样实现,另一个采用 void-[=65= 的第三个模板参数]ing 函数:void(TCaller::*TMethod)(const TMessage &)
。在 void returning 函数的句柄函数中,我将调用指针函数,并且 return true.
但我想知道是否有一种方法可以使用相同的 Invoker
class 名称,这样用户就不必将正确的 Invoker
与 return 他的句柄函数的值。有点像函数重载 - 但对于模板 classes.
当然,如果我只是创建了两个具有相同名称的 classes(每个都采用不同的 return 类型的函数模板参数),编译器会要求重新声明模板参数。
所以我试图通过模板部分特化来实现这一点,但无法找到一种方法来定义第三个模板参数而不会出现编译错误——我什至不确定这是正确的方法。
当我尝试这个时:
template <typename TMessage, typename TCaller, typename TMethod>
class Invoker : public Subscription<TMessage> {
};
template <typename TMessage, typename TCaller, bool(TCaller::*TMethod)(const TMessage &)>
class Invoker<TMessage, TCaller, TMethod> {
public:
Invoker(TCaller *caller) :
m_caller(*caller) {
}
virtual bool handle(const TMessage &message) {
return (m_caller.*TMethod)(message);
}
protected:
TCaller &m_caller;
};
template <typename TMessage, typename TCaller, void(TCaller::*TMethod)(const TMessage &)>
class Invoker<TMessage, TCaller, TMethod> {
public:
Invoker(TCaller *caller) :
m_caller(*caller) {
}
virtual bool handle(const TMessage &message) {
(m_caller.*TMethod)(message);
return true;
}
protected:
TCaller &m_caller;
};
我在两个 Invoker 实现上都遇到了以下编译错误:
error: type/value mismatch at argument 3 in template parameter list for template class Invoker
error: expected a type, got TMethod
逻辑 class 上的以下编译错误(对于每个 Invoker):
In constructor Logic::Logic():
error: type/value mismatch at argument 3 in template parameter list for template class Invoker
error: expected a type, got &Logic::handleSubscription1
error: invalid conversion from Logic* const to int
error: cannot convert int* to Subscription* in initialization
我做错了什么,模板偏特化是否可行?
如果有任何可能的解决方案,我想知道它在 c++11 和 c++98 中是否可行。
谢谢。
你可以
template <typename TMethod, TMethod method> class Invoker;
// partial specialization for TMethod = bool(TCaller::*)(const TMessage &)
template <typename TMessage, typename TCaller, bool(TCaller::*method)(const TMessage &)>
class Invoker<bool(TCaller::*)(const TMessage &), method> :
public Subscription<TMessage>
{
public:
explicit Invoker(TCaller& caller) : m_caller(caller) {}
virtual bool handle(const TMessage &message) {
return (m_caller.*method)(message);
}
protected:
TCaller &m_caller;
};
// partial specialization for TMethod = void(TCaller::*)(const TMessage &)
template <typename TMessage, typename TCaller, void(TCaller::*method)(const TMessage &)>
class Invoker<void(TCaller::*)(const TMessage &), method> :
public Subscription<TMessage>
{
public:
explicit Invoker(TCaller& caller) : m_caller(*caller) {}
virtual bool handle(const TMessage &message) {
(m_caller.*method)(message);
return true;
}
protected:
TCaller &m_caller;
};
用法是这样的:
class Logic {
public:
Logic() :
m_subscription1(std::make_unique<Invoker<decltype(&Logic::handleSubscription1), &Logic::handleSubscription1>>(*this)),
m_subscription2(std::make_unique<Invoker<decltype(&Logic::handleSubscription2), &Logic::handleSubscription2>>(*this)) {
}
bool handleSubscription1(const MyMessage &message) {
// handle message... uses class members
return true;
}
void handleSubscription2(const MyMessage &message) {}
private:
std::unique_ptr<Subscription<MyMessage>> m_subscription1;
std::unique_ptr<Subscription<MyMessage>> m_subscription2;
};
考虑以下摘要 Subscription
class:
template <typename TMessage>
class Subscription {
public:
virtual ~Subscription() {}
virtual bool handle(const TMessage &) = 0;
};
在某些情况下,如果一个 class 可以单独实现此抽象 class 多次 可能会很方便 - 即使是相同的 TMessage
- 和不强制继承。
为了实现这一点,我使用模板指针按以下方式运行:
template <typename TMessage, typename TCaller, bool(TCaller::*TMethod)(const TMessage &)>
class Invoker : public Subscription<TMessage> {
public:
Invoker(TCaller *caller) :
m_caller(*caller) {
}
virtual bool handle(const TMessage &message) {
return (m_caller.*TMethod)(message);
}
protected:
TCaller &m_caller;
};
这允许创建抽象 class 的模板生成实现,如下所示:
(而不是在几个不同的 classes 中实现并在它们之间共享对象):
struct MyMessage {};
class Logic {
public:
Logic() :
m_subscription1(new Invoker<MyMessage, Logic, &Logic::handleSubscription1>(this)),
m_subscription2(new Invoker<MyMessage, Logic, &Logic::handleSubscription2>(this)) {
}
~Logic() {
delete m_subscription1;
delete m_subscription2;
}
bool handleSubscription1(const MyMessage &message) {
// handle message... uses class members
return true;
}
bool handleSubscription2(const MyMessage &message) {
// handle message... uses class members
return false;
}
private:
Subscription<MyMessage> *m_subscription1;
Subscription<MyMessage> *m_subscription2;
};
问题是,我想让用户模块(即 Logic
class)实现 void
句柄函数以及 bool
选项。
现在,我当然可以创建 2 个不同的 Invoker
classes - 一个像上面的代码一样实现,另一个采用 void-[=65= 的第三个模板参数]ing 函数:void(TCaller::*TMethod)(const TMessage &)
。在 void returning 函数的句柄函数中,我将调用指针函数,并且 return true.
但我想知道是否有一种方法可以使用相同的 Invoker
class 名称,这样用户就不必将正确的 Invoker
与 return 他的句柄函数的值。有点像函数重载 - 但对于模板 classes.
当然,如果我只是创建了两个具有相同名称的 classes(每个都采用不同的 return 类型的函数模板参数),编译器会要求重新声明模板参数。
所以我试图通过模板部分特化来实现这一点,但无法找到一种方法来定义第三个模板参数而不会出现编译错误——我什至不确定这是正确的方法。
当我尝试这个时:
template <typename TMessage, typename TCaller, typename TMethod>
class Invoker : public Subscription<TMessage> {
};
template <typename TMessage, typename TCaller, bool(TCaller::*TMethod)(const TMessage &)>
class Invoker<TMessage, TCaller, TMethod> {
public:
Invoker(TCaller *caller) :
m_caller(*caller) {
}
virtual bool handle(const TMessage &message) {
return (m_caller.*TMethod)(message);
}
protected:
TCaller &m_caller;
};
template <typename TMessage, typename TCaller, void(TCaller::*TMethod)(const TMessage &)>
class Invoker<TMessage, TCaller, TMethod> {
public:
Invoker(TCaller *caller) :
m_caller(*caller) {
}
virtual bool handle(const TMessage &message) {
(m_caller.*TMethod)(message);
return true;
}
protected:
TCaller &m_caller;
};
我在两个 Invoker 实现上都遇到了以下编译错误:
error: type/value mismatch at argument 3 in template parameter list for template class Invoker
error: expected a type, got TMethod
逻辑 class 上的以下编译错误(对于每个 Invoker):
In constructor Logic::Logic():
error: type/value mismatch at argument 3 in template parameter list for template class Invoker
error: expected a type, got &Logic::handleSubscription1
error: invalid conversion from Logic* const to int
error: cannot convert int* to Subscription* in initialization
我做错了什么,模板偏特化是否可行? 如果有任何可能的解决方案,我想知道它在 c++11 和 c++98 中是否可行。
谢谢。
你可以
template <typename TMethod, TMethod method> class Invoker;
// partial specialization for TMethod = bool(TCaller::*)(const TMessage &)
template <typename TMessage, typename TCaller, bool(TCaller::*method)(const TMessage &)>
class Invoker<bool(TCaller::*)(const TMessage &), method> :
public Subscription<TMessage>
{
public:
explicit Invoker(TCaller& caller) : m_caller(caller) {}
virtual bool handle(const TMessage &message) {
return (m_caller.*method)(message);
}
protected:
TCaller &m_caller;
};
// partial specialization for TMethod = void(TCaller::*)(const TMessage &)
template <typename TMessage, typename TCaller, void(TCaller::*method)(const TMessage &)>
class Invoker<void(TCaller::*)(const TMessage &), method> :
public Subscription<TMessage>
{
public:
explicit Invoker(TCaller& caller) : m_caller(*caller) {}
virtual bool handle(const TMessage &message) {
(m_caller.*method)(message);
return true;
}
protected:
TCaller &m_caller;
};
用法是这样的:
class Logic {
public:
Logic() :
m_subscription1(std::make_unique<Invoker<decltype(&Logic::handleSubscription1), &Logic::handleSubscription1>>(*this)),
m_subscription2(std::make_unique<Invoker<decltype(&Logic::handleSubscription2), &Logic::handleSubscription2>>(*this)) {
}
bool handleSubscription1(const MyMessage &message) {
// handle message... uses class members
return true;
}
void handleSubscription2(const MyMessage &message) {}
private:
std::unique_ptr<Subscription<MyMessage>> m_subscription1;
std::unique_ptr<Subscription<MyMessage>> m_subscription2;
};