Добавить математического сахара в (multi)set

mrgordonfreman
mrgordonfreman

Как минимум хотелось бы иметь перегрузки операторов +=, \= для выражения объединения и разности множеств.

Определяем множество целых чисел p.

std::set<int> p;

Присваиваем p множество {1, 3, 5}.

p = {1, 3, 5};

Здесь все хорошо, есть перегрузка оператора = со списком инициализации. Оперируем символами, а не контейнером.

Далее хотим добавить новые элементы в множество p, т.е. выполнить объединение.

p += {5, 7, 11};

Но так, к сожалению, не работает. Приходится опускаться на уровень контейнера и вызывать соответствующий метод.

p.insert({5, 7, 11});

Добавление через оператор += близко к описанию алгоритма на псевдокоде. Его можно выразить через уже имеющийся insert

set& operator+=( std::initializer_list<value_type> il ) {
    insert(il);
    return *this;
}

template<class Comp, class Alloc>
set& operator+=( std::set<value_type, Comp, Alloc> const& oth ) {
    insert(oth.begin(), oth.end());
    return *this;
}

Перегрузка для отдельного значения не нужна, т.к. запись через список инициализации {1} наглядно показывает, что работаем с множествами.

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

Аналогичным образом можно определить оператор /= для разности множеств.

set& operator/=( std::initializer_list<value_type> il ) {
    for (auto& x: il)
        erase(x);
    return *this;
}

template<class Comp, class Alloc>
set& operator/=( std::set<value_type, Comp, Alloc> const& oth ) {
    for (auto& x: oth)
        erase(x);
    return *this;
}

 

2
рейтинг
6 комментариев
languagelawyer

О нет, только не member-функции!

languagelawyer
Andrey Davydov

Во-первых, это сломает существующий код:

using namespace boost::assign;

std::set<int> s;
s += 1,2,3;

Во-вторых, мотивация "на контестах надо экономить число нажатий клавиш" очень слабая.

Andrey Davydov
mrgordonfreman

Andrey Davydov, вроде бы код не ломается

#include <boost/assign.hpp>
#include <iostream>

using namespace boost::assign;

template<class T, class Comp, class Alloc>
std::set<T, Comp, Alloc>& operator +=(std::set<T, Comp, Alloc>& s, std::initializer_list<T> il)
{
    s.insert(il);
    return s;
}

int main()
{
    std::set<int> s;
    s += 1,2,3;
    s += {3,4,5};
    for (auto&x : s)
        std::cout << x << ' ';
    std::cout << std::endl;
}
mrgordonfreman
Andrey Davydov

mrgordonfreman, Вы правы, не ломает, зря я поленился проверить. Тем не менее Ваше предложение мне все равно не нравится, как-то оно неконсистентно с остальной STL. Почему тогда, к примеру, у vectorpush_back а не operator += ?

Andrey Davydov
Ivan Azoyan

Andrey Davydov, справедливости  ради (насчёт консистентности STL) замечу, что в basic_string есть такая перегрузка. http://cpp.sh/8ogdg

#include <iostream>
#include <string>

int main() {
  std::basic_string<int> v = { 1, 2, 3, 4 };
  v += 5;
  v += { 6, 7 };
  for (auto i : v) std::cout << i << " "; // 1 2 3 4 5 6 7
}
Ivan Azoyan
Andrey Davydov

Ivan Azoyan, вот же ж. Иметь operator +=(initializer_list) для basic_string, но не иметь его для вектора, это неожиданно.

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