Подмешивание новых методов уже существующим классам

valera_ee
valera_ee

Думаю, многие согласятся, что подход STL не очень удобен в использовании, когда алгоритмы живут сами по себе, а типы данных, к которым применяются эти алгоритмы, сами по себе. Не всегда очевидно какой алгоритм можно или нельзя использовать с тем или иным контейнером. Но STL уже не изменить, но можно улучшить.
На примере класса std::vector покажу, как я сделал его немного удобнее для себя.

Есть шаблонный класс, которы реализует некоторый алгоритм, например, заполнение контейнера некоторым значением:

template <class Container>
class add_fill
{
public:
    template<class Arg>
    Container& fill(Arg &&arg) {
        auto p = static_cast<Container*>(this);
        std::fill(p->begin(), p->end(), arg);
        return (*p);
    }
};

Теперь конструирую свой вектор на основе std:: vector :

template <class T>
class my_vector : public std::vector<T>,
                  public add_fill<vector<T>>
{
public:
    template <class ...Args>
    vector(Args&& ...args) : std::vector<T>(args...) {}
    vector(std::initializer_list<T> init) : std::vector<T>(init) {}
};

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

Куда удобнее написать что-то вроде:

template<class T>
using my_vector_t = std::vector<T, add_fill, add_copy, add_find, add_sort, add_transform>;

my_vector_t<int> my_vec;
my_vec.resize(N);
my_vec.fill(-200_dB);
my_vec.transform_from(other_vec, [](int val){ return 10*val - 5; });

А для ещё большего удобства делать возвращаемый тип не void, а ссылку на себя, в таком случае можно писать так:

my_vec.resize(N).fill(-200_dB).transform_from(other_vec, [](int val){ 
    return 10*val - 5; 
});

Этот приём позволяет много всего интересного и мой пример лишь малая часть, очень бы хотелось, что бы STL из коробки давал возможность создавать удобные типы на основе уже существующих без наследования.

-3
рейтинг
6 комментариев
develoit

что мешает нужные алгоритмы свободными функциями сделать??
запилят же когда-нибудь f(x) -> x.f и будет вам счастье)

develoit
valera_ee

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

Например, класс std::array имеет метод fill(), а std::vector - нет, похоже на бардак в STL. Очень длинные строчки кода где используются алгоритмы, Ranges хорошо упростят код, но не решат проблему в целом.

valera_ee
maxon

valera_ee, контейнеры, алгоритмы и итераторы -- это не "корень проблемы", а как раз решение многих трудностей. Способ хранения данных и алгоритмы их обработки -- это разные сущности, с какой стати их приколачивать друг к другу гвоздями, ещё и внутри стандартной либы? Это и в прикладном варианте попахивает.

Сложности с "подходит алгоритм к контейнеру или нет" мне тоже непонятны. Большинство - подходит. Практически все контейнеры имеют ForwardIterator, а большинству алгоритмов этого достаточно. 
Попытка получить RandomAccessIterator у std::forward_list закономерно закончится ошибкой, но я бы не назвал эту ситуацию "непонятно подходит или нет". 

maxon
valera_ee

maxon, ну вот простой житейский пример, я хочу удалить из контейнера элементы неудовлетворяющие предикату, я делаю 2 действия:
 1 - дергаю внешнюю функцию std::remove_if
 2 - затем возвращённый итератор передаю на вход самого контейнера

people.erase(std::remove_if(people.begin(), people.end(), is_valid), people.end());

Ну проще же писать: people.remove_if(is_valid);

 

 

valera_ee
develoit

valera_ee, ну ведь и не сложнее писать: remove_if(people, is_valid);

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

develoit
Топунов Владимир Андреевич

Есть вариант получше Unified Call Syntax

 
Топунов Владимир Андреевич
Обновлено 
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).
Все предложения