Как выделить шаблонность из функции?

243
15 августа 2017, 15:38

Имеем - шаблонная функция, еще и рекурсивная, в которой много чего подтянуто из разных (заголовочных) файлов, а шаблонность только одна - запись найденного значения в итератор. Что-то примерно такое

template<typename Itor>
void terribleFunction(Itor it, type1 param1, type2 param2, ...)
{
    // Всякие дела
    for(....
    {
        // И еще дела
        // Первое использование it
        if(...) terribleFunctiom(it,p1,p2,...);
        // И еще...
        // Второе использование it
        if (...) *it++ = что-то;  
        // И еще...
    }
}

Примерно так. Хочется максимально спрятать весь код - в котором ничего шаблонного - или в библиотеку, или в отдельный файл - вобщем, как минимум постараться не плодить зависимости в заголовочном файле, выписывая в нем весь код, постараться максимально убрать его в какие-нибудь вспомогательные функции, что ли. Но что-то что ни придумываю - все через одно неприличное место...

Какой бы тут хитрый метод применить, намекните?...

Answer 1

Если единственное использование - это X x = expr; *it++ = x;, то эту операцию можно обернуть в std::function<void(X)> f, передавать не итератор а эту функцию, использовать как f(x).

Либо можно передавать класс с виртуальными функциями.

Answer 2

По сути, все что вам нужно это полиморфное поведение вашего итератора. Сейчас вы достигаете полиморфизма за счет шаблонов. Можно достичь того же эффекта при помощи наследования и виртуальных методов.

Для начала объявим интерфейс итератора:

class IIterator{
public:
    virtual void next() = 0;
    virtual void setValue(int value) = 0;
    virtual int value() const = 0;
    virtual ~IIterator(){}
};

Думаю вы знаете тип значения, которое хотите писать в итератор. Для примера я взял int.

Теперь нам нужна конкретная реализация, причем для всех возможных итераторов. Да, снова шаблоны:

template<class It>
class Iterator : public IIterator{
    It _iterator;
public:
    explicit Iterator(const It &iterator):
        _iterator(iterator)
    {}
    void next(){
        ++_iterator;
    }
    void setValue(int value){
        *_iterator = value;
    }
    int value() const{
        return *_iterator;
    }
};

Теперь возьмем весь код из void terribleFunction(Itor it), перенесем его в функцию void terribleFunctionHelper(IIterator &it), и внесем некоторые изменения в использование итераторов:

void terribleFunctionHelper(IIterator &it){
    //...
    it.next();         //Раньше тут было ++it;
    it.setValue(42);   //Раньше тут было *it = 42;
    //...
}

Код void terribleFunction(Itor it) теперь станет таким:

template<typename It>
void terribleFunction(It it){
    Iterator<It> iterator(it);
    terribleFunctionHelper(iterator);
}

В результате этих нехитрых манипуляций, все зависимости оказались в нешаблонной terribleFunctionHelper. Можно смело переносить ее код в cpp файл.

Полный пример

READ ALSO
Доступ к членам класса через .* и -&gt;*

Доступ к членам класса через .* и ->*

В каких случаях используются операторы x*ptm или p->*ptm? Прошу привести минимальный пример, где это может понадобиться

222
&ldquo;Ошибка конвертации&rdquo; в C/C++ [требует правки]

“Ошибка конвертации” в C/C++ [требует правки]

ЗдравствуйтеКто знает, почему в этом проэкте две ошибки? "invalid conversion from 'int()(const char)' to 'const void*' [-fpermissive]"

254
Утечка памяти в функции с++

Утечка памяти в функции с++

Есть такое задание :

229
Проблема с создание вектора в классе, С++

Проблема с создание вектора в классе, С++

Я создаю вектор ссылок на объекты моего класса в главной функции - всё работает замечательноСоздаю схожий вектор в ином классе - всё работать...

199