Как перегрузить метод базового класса, передаваемый в качестве параметра в шаблон класса в C ++? - PullRequest
2 голосов
/ 24 июня 2019

Существует два класса:

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

Теперь класс (ы), который я строю, может быть производным от любого класса.Но есть некоторый общий вспомогательный код, поэтому я хочу выделить его в базовый класс.Этот общий код должен вызываться из foo и должен принимать те же аргументы, что и соответствующий метод foo.Поэтому я объявляю этот класс шаблона, но не знаю, возможно ли «извлечь» сигнатуру foo из аргумента шаблона (который является базовым классом - либо A, либо B):

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 (и компиляция должна завершиться неудачей, если Base вообще не предоставляет foo).

1 Ответ

2 голосов
/ 24 июня 2019

Одним из решений, которое я вижу, является добавление другого параметра шаблона для подписи метода и передача его явно при специализации.

Это на правильном пути, но вам не нужно передаватьэто явно;Вы можете извлечь тип из базового класса:

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;

[Живой пример]

Это работает с использованием частичной специализации шаблона класса для декомпозиции типа функции.Параметр шаблона Foo из BaseSelector будет содержать тип указателя на элемент foo.Чтобы получить этот тип, мы используем decltype(&Base::foo), аргумент по умолчанию для этого параметра.

Однако нам необходимо получить доступ к отдельным типам аргументов из этого типа.Обычно это делается с использованием частичной специализации шаблона, как здесь.По сути, основной шаблон говорит: «Этот шаблон класса принимает два типа, Base и Foo».Они типы, и мы больше ничего о них не знаем.Мы также не используем их ни для чего (основной шаблон даже не определен).

Затем мы предоставляем специализацию.Это фактически говорит: «Когда тип Foo оказывается указателем на функцию-член Base, которая возвращает void и принимает аргументы типа Arg..., то сделайте это: {частично специализированное определение класса}».На практике это просто способ присвоения имен различным компонентам типа указатель на член.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...