简体   繁体   English

模板指向函数的部分模板特化

[英]partial template specialization for template pointer to function

Consider the following abstract Subscription class: 请考虑以下抽象Subscription类:

template <typename TMessage>
class Subscription {
public:
    virtual ~Subscription() {}
    virtual bool handle(const TMessage &) = 0;
};

In some cases, it could be convenient if one class alone could implement this abstract class several times - even for the same TMessage - and not force inheritance. 在某些情况下,如果单独一个类可以多次实现此抽象类 - 即使对于相同的TMessage - 不是强制继承,则可能很方便。

To achieve this I am using a template pointer to function in the following way: 为了实现这一点,我使用模板指针以下列方式运行:

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

This allows creating template-generated implementers of the abstract class like this: 这允许创建模板生成的抽象类的实现,如下所示:
(instead of implementing in several different classes and sharing objects between them): (而不是在几个不同的类中实现并在它们之间共享对象):

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

The thing is, that I would like to allow the user modules (ie Logic class) an implementation of a void handle function as well as a bool option. 问题是,我想允许用户模块(即Logic类)实现void句柄函数以及bool选项。

Now, of course I could create 2 different Invoker classes - one implemented just like in the above code, and another taking a 3rd template argument of a void-returning function: void(TCaller::*TMethod)(const TMessage &) . 现在,我当然可以创建两个不同的Invoker类 - 一个像上面的代码一样实现,另一个使用void返回函数的第三个模板参数: void(TCaller::*TMethod)(const TMessage &) In the handle function of the void returning function I would call the pointered function, and return true. 在void返回函数的handle函数中,我将调用指针函数,并返回true。

But I was wondering it there's a way to use the same Invoker class name so that the user won't have to match the right Invoker to the return value of his handle function. 但我想知道有一种方法可以使用相同的Invoker类名,这样用户就不必将正确的Invoker与其句柄函数的返回值相匹配。 Kinda like function overloading - but for template classes. 有点像函数重载 - 但对于模板类。

Of course if I just created two classes with the same name (each taking different return type function template argument), the compiler would scream for redeclaration of template parameter. 当然如果我刚刚创建了两个具有相同名称的类(每个类采用不同的返回类型函数模板参数),编译器会尖叫重新声明模板参数。
So I tried to achieve this with template partial specialization but couldn't figure out a way to define the 3rd template argument without getting a compilation error - I'm not even sure it's the right way to go at it. 所以我尝试使用模板部分特化来实现这一点,但是无法找到一种方法来定义第三个模板参数而不会出现编译错误 - 我甚至不确定这是正确的方法。

When I tried this: 当我尝试这个时:

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

I got the following compilation errors on both Invoker implementations: 我在两个Invoker实现上都遇到了以下编译错误:

error: type/value mismatch at argument 3 in template parameter list for template class Invoker 错误:模板类Invoker的模板参数列表中参数3的类型/值不匹配
error: expected a type, got TMethod 错误:期望一个类型,得到了TMethod

And the following compilation errors on the Logic class (for each Invoker): Logic类上的以下编译错误(对于每个Invoker):

In constructor Logic::Logic(): 在构造函数Logic :: Logic()中:
error: type/value mismatch at argument 3 in template parameter list for template class Invoker 错误:模板类Invoker的模板参数列表中参数3的类型/值不匹配
error: expected a type, got &Logic::handleSubscription1 错误:期望一个类型,得到&Logic :: handleSubscription1
error: invalid conversion from Logic* const to int 错误:从Logic * const到int的无效转换
error: cannot convert int* to Subscription* in initialization 错误:初始化时无法将int *转换为Subscription *

What am I doing wrong and is this possible with template partial specialization? 我做错了什么,这可能与模板部分专业化有关吗? If there's any possible solution I would like to know if it's feasible in c++11 as well as c++98. 如果有任何可能的解决方案,我想知道它是否可以在c ++ 11和c ++ 98中使用。

Thanks. 谢谢。

You may do 你可能会这样做

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

And usage is something like: 用法如下:

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

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

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