Может ли шаблон Proxy вмещать функции шаблона?

У меня есть класс с функцией шаблона:

foo.h:

class Foo {
public:
int some_function();
bool some_other_function(int a, const Bar& b) const;

template<typename T>
int some_template_function(const T& arg);
};

template<typename T>
int Foo::some_template_function(const T& arg){
/*...generic implementation...*/
}

Теперь я подошел к моменту, когда я хочу получить доступ к Foo через прокси-класс, как в Шаблон прокси-дизайна.


Интуитивно я хотел бы провести рефакторинг следующим образом (следующий код неверен, но он выражает мой «идеализированный» API):

FooInterface.h:

class FooInterface {
public:
virtual int some_function()=0;
virtual bool some_other_function(int a, const Bar& b) const=0;

template<typename T>
virtual int some_template_function(const T& arg)=0;
};

FooImpl.h:

#include "FooInterface.h"
/** Implementation of the original Foo class **/
class FooImpl : public FooInterface {
public:
int some_function();
bool some_other_function(int a, const Bar& b) const;

template<typename T>
int some_template_function(const T& arg);
};

template<typename T>
int FooImpl::some_template_function(const T& arg){
/*...generic implementation...*/
}

FooProxy.h:

#include "FooInterface.h"
class FooProxy : public FooInterface{
protected:
FooInterface* m_ptrImpl; // initialized somewhere with a FooImpl*; unimportant in the context of this question
public:
int some_function()
{ return m_ptrImpl->some_function(); }
bool some_other_function(int a, const Bar& b) const
{ return m_ptrImpl->some_other_function(a,b); }

template<typename T>
int some_template_function(const T& arg)
{ return m_ptrImpl->some_template_function(arg); }
};

Но этот код с треском проваливается.

Прежде всего, FooImpl не может скомпилироваться, так как функции шаблона класса не могут быть виртуальными.

Более того, даже если я поигрался с определением some_template_function, даже если я зайду так далеко, как переместу его в конкретный класс или какую-то другую махинацию присяжных, это все равно приведет к хаосу с точки зрения наличия прокси-класса в первую очередь, потому что код шаблона должен быть определен в заголовок и в комплекте. Это заставит FooProxy.h включать FooImpl.h, а также FooImpl.h нужны все детали реализации и файл-включения, необходимые для реализации some_template_function, Так что, если я использую шаблон Proxy для того, чтобы скрыть детали реализации, отдалиться от конкретной реализации и избежать ненужных включений файлов, то мне не повезло.

Есть ли способ применить шаблон Proxy или его разновидность к классу с шаблонными функциями? Или это невозможно в C ++?


Контекст: В данный момент я пытаюсь предоставить прокси-доступ к группе классов, в которой уже есть встроенный механизм ведения журнала. Единственный API, который у меня есть для этого журнала, использует переменные шаблоны, поэтому невозможно предсказать комбинации параметров, с которыми он будет использоваться. Я бы хотел, чтобы разделение между реализацией и клиентом, использующим прокси, было как можно более чистым, и мне нужно минимизировать зависимости от клиента до реализации, но мне нужно, чтобы они записывали в один и тот же журнал.

Тем не менее, я заинтересован в этом вопросе за пределами моей непосредственной проблемы. Меня удивляет, что шаблоны втыкают такую ​​дыру в основной шаблон дизайна, и что я нигде не нашел, чтобы эта проблема решалась.

0

Решение

Оболочка / прокси для класса, который имеет шаблонный интерфейс, всегда будет требовать, чтобы определение класса шаблона было видно в файле заголовка для кода, который вызывает обертку. Это связано с тем, что код, сгенерированный для шаблонного интерфейса, зависит от типов аргументов, с которыми он вызывается.

Если вы застряли с существующей шаблонной реализацией FooImplтогда, как пишет @mars в комментариях, ваш единственный вариант:

template <class Implementation>
class FooProxy
{
Implementation * m_ptrImpl;
//...
};

Если вы можете изменить существующую реализацию, идеальным решением будет рефакторинг шаблонных методов и разделение их на два уровня; один слой, который зависит от типов аргументов, и второй слой, который не зависит. Код в существующих методах, который зависит от типов аргументов, должен быть одинаковым во всех реализациях, поэтому этот уровень можно переместить в метод абстрактного класса интерфейса. Оставшийся код, который не зависит от типов аргументов, можно оставить в не шаблонном методе класса реализации, что означает, что детали реализации могут быть скрыты в файле .cpp.

Вот пример, основанный на сценарии журнала, который поддерживает запись произвольных типов:

LogInterface.h

class LogInterface {
public:
template<typename T>
void write(const T& arg)
{
// converts from 'T' to array of characters.
// calls non-template 'write' as many times as necessary.
}

virtual void write(const char* p, std::size_t n)=0;
};

LogImpl.h

#include "LogInterface.h"
/** Implementation of the original Log class **/
class LogImpl : public LogInterface {
public:
void write(const char* p, std::size_t n);
};

LogProxy.h

#include "LogInterface.h"
class LogProxy : public LogInterface{
protected:
LogInterface* m_ptrImpl; // initialized somewhere with a LogImpl*
public:
void write(const char* p, std::size_t n)
{ m_ptrImpl->write(p, n); }
};
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]