2

有两个类:

class A {
public:
    virtual void foo( int bar );
}
class B {
    virtual void foo( string bar, int baz);
}

现在,我正在构建的类可以派生自任一类。但是有一些常见的帮助代码,所以我想把它分解成一个基类。必须调用此公共代码,并且应采用与相应方法foo相同的参数。foo所以我声明了这个模板类,但不知道是否可以foo从模板参数中“提取”的签名(这是一个基类 - 要么 要么AB

template<class Base>
class CommonBase : public Base {
    public:
        // how do I overload Base::foo here?
        void foo(/*Base::foo arguments here*/) {
            commonCode(/*Base::foo arguments here*/);
        }
    protected:
        // how do I define commonCode with Base::foo signature below?
        void commonCode(/*Base::foo arguments here*/) { ... }
}

我对 C++ 模板没有什么经验,所以想知道——这有可能吗?我看到的一种解决方案是为方法签名添加另一个模板参数,并在专门化时显式传递它。但是感觉是多余的,因为foo签名的知识已经包含在类参数中(如果根本不提供,Base编译应该会失败)。Basefoo

4

1 回答 1

2

我看到的一种解决方案是为方法签名添加另一个模板参数,并在专门化时显式传递它。

这是在正确的轨道上,但您不必明确地通过它;您可以从基类中提取类型:

template<class Base, class... Arg>
class CommonBaseImpl : public Base {
    public:
        // how do I overload Base::foo here?
        void foo(Arg... arg) override {
            commonCode(std::forward<Arg>(arg)...);
        }
    protected:
        // how do I define commonCode with Base::foo signature below?
        void commonCode(Arg... arg) { ... }
};

template <class Base, class Foo = decltype(&Base::foo)>
struct BaseSelector;

template <class Base, class... Arg>
struct BaseSelector<Base, void (Base::*)(Arg...)>
{
  using type = CommonBaseImpl<Base, Arg...>;
};

template <class Base>
using CommonBase = typename BaseSelector<Base>::type;

[现场示例]

这通过使用类模板部分特化来分解函数类型来工作。的模板参数FooBaseSelector保存指向的成员指针的类型foo。为了获得这种类型,我们使用decltype(&Base::foo)该参数的默认参数 。

但是,我们需要从该类型中访问各个参数类型。这通常使用模板部分特化来完成,就像这里一样。基本上,主模板说:“这个类模板有两种类型,BaseFoo。” 他们是类型,我们对他们一无所知。我们也不会将它们用于任何事情(甚至没有定义主模板)。

然后,我们提供专业化。这实际上是说:“当类型Foo恰好是指向Base其返回void并接受类型参数的成员函数的指针时Arg...,请执行以下操作:{部分专门化的类定义}”。在实践中,它只是为指向成员类型的各个组件分配名称的一种方式。

于 2019-06-24T18:53:16.470 回答