Форум » C/C++ » Предложение по включению в стандарт C++ новых обобщенных функций std::reverse и std::sort » Ответить

Предложение по включению в стандарт C++ новых обобщенных функций std::reverse и std::sort

Сыроежка: В подавляющем большинстве случаев стандартные алгоритмы std::reverse и std::sort (и аналогичные им функции члены классов std::forward_list и std::list) вызываются для всего контейнера. Поэтому было бы целесообразно включить в стандарт C++ соответствующие обобщенные функции std::reverse и std::sort, которые в качестве параметра имели бы ссылку на контейнер. Это упростило бы работу программиста по рутинному написанию вызовов соответствующих функций с указанием итераторов начала списка элементов контейнера и его конца. Ниже приведен демонстрационный пример, иллюстрирующий идею предложения. [pre2] #include <iostream> #include <algorithm> #include <iterator> #include <functional> #include <vector> #include <forward_list> #include <list> namespace N1 // std { template <typename T> void reverse( T &c ) { std::reverse( std::begin( c ), std::end( c ) ); } template <typename T, typename Allocator> void reverse( std::forward_list<T, Allocator> &f ) { f.reverse(); } template <typename T, typename Allocator> void reverse( std::list<T, Allocator> &l ) { l.reverse(); } template <typename T> void sort( T &c ) { std::sort( std::begin( c ), std::end( c ) ); } template <typename T, typename Allocator> void sort( std::forward_list<T, Allocator> &f ) { f.sort(); } template <typename T, typename Allocator> void sort( std::list<T, Allocator> &l ) { l.sort(); } template <typename T, typename Compare> void sort( T &c, Compare comp ) { std::sort( std::begin( c ), std::end( c ), comp ); } template <typename T, typename Allocator, typename Compare> void sort( std::forward_list<T, Allocator> &f, Compare comp ) { f.sort( comp ); } template <typename T, typename Allocator, typename Compare> void sort( std::list<T, Allocator> &l, Compare comp ) { l.sort( comp ); } } // end of N1 int main() { int a[3] = { 1, 2, 3 }; std::forward_list<int> f( std::begin( a ), std::end( a ) ); std::list<int> l( std::begin( a ), std::end( a ) ); std::vector<int> v( std::begin( a ), std::end( a ) ); std::cout << "a:\t"; for ( int x : a ) std::cout << x << ' '; std::cout << std::endl; std::cout << "f:\t"; for ( int x : f ) std::cout << x << ' '; std::cout << std::endl; std::cout << "l:\t"; for ( int x : l ) std::cout << x << ' '; std::cout << std::endl; std::cout << "v:\t"; for ( int x : v ) std::cout << x << ' '; std::cout << std::endl; std::cout << std::endl; N1::reverse( a ); N1::reverse( f ); N1::reverse( l ); N1::reverse( v ); std::cout << "a:\t"; for ( int x : a ) std::cout << x << ' '; std::cout << std::endl; std::cout << "f:\t"; for ( int x : f ) std::cout << x << ' '; std::cout << std::endl; std::cout << "l:\t"; for ( int x : l ) std::cout << x << ' '; std::cout << std::endl; std::cout << "v:\t"; for ( int x : v ) std::cout << x << ' '; std::cout << std::endl; std::cout << std::endl; N1::sort( a ); N1::sort( f ); N1::sort( l ); N1::sort( v ); std::cout << "a:\t"; for ( int x : a ) std::cout << x << ' '; std::cout << std::endl; std::cout << "f:\t"; for ( int x : f ) std::cout << x << ' '; std::cout << std::endl; std::cout << "l:\t"; for ( int x : l ) std::cout << x << ' '; std::cout << std::endl; std::cout << "v:\t"; for ( int x : v ) std::cout << x << ' '; std::cout << std::endl; std::cout << std::endl; N1::sort( a, std::greater<int>() ); N1::sort( f, std::greater<int>() ); N1::sort( l, std::greater<int>() ); N1::sort( v, std::greater<int>() ); std::cout << "a:\t"; for ( int x : a ) std::cout << x << ' '; std::cout << std::endl; std::cout << "f:\t"; for ( int x : f ) std::cout << x << ' '; std::cout << std::endl; std::cout << "l:\t"; for ( int x : l ) std::cout << x << ' '; std::cout << std::endl; std::cout << "v:\t"; for ( int x : v ) std::cout << x << ' '; std::cout << std::endl; std::cout << std::endl; } [/pre2]

Ответов - 3

Сыроежка: Похоже с включением в стандарт C++ выражений требований (requires expressions) будет не сложно написать обобщенные функции std::sort и std::reverse. Я еще не достаточно изучил это нововведение, но тем не менее представленный ниже код выполняет поставленную задачу. Естественно выражения требований у функций могут быть еще уточнены. [pre2] #include <iostream> #include <forward_list> #include <vector> #include <iterator> #include <algorithm> template <typename Container> void sort( Container &container ) requires requires() { &Container::sort; } { std::cout << "sort with requires is called.\n"; container.sort(); } template <typename Container> void sort( Container &container ) { std::cout << "sort without requires is called.\n"; std::sort( std::begin( container ), std::end( container ) ); } template <typename Container> void reverse( Container &container ) requires requires() { &Container::reverse; } { std::cout << "reverse with requires is called.\n"; container.reverse(); } template <typename Container> void reverse( Container &container ) { std::cout << "reverse without requires is called.\n"; std::reverse( std::begin( container ), std::end( container ) ); } int main() { std::forward_list<int> lst = { 3, 2, 1 }; for ( const auto &item : lst ) std::cout << item << ' '; std::cout << '\n'; sort( lst ); for ( const auto &item : lst ) std::cout << item << ' '; std::cout << '\n'; reverse( lst ); for ( const auto &item : lst ) std::cout << item << ' '; std::cout << '\n'; std::cout << '\n'; std::vector<int> v = { 3, 2, 1 }; for ( const auto &item : v ) std::cout << item << ' '; std::cout << '\n'; sort( v ); for ( const auto &item : v ) std::cout << item << ' '; std::cout << '\n'; reverse( v ); for ( const auto &item : v ) std::cout << item << ' '; std::cout << '\n'; std::cout << '\n'; int a[] = { 3, 2, 1 }; for ( const auto &item : a ) std::cout << item << ' '; std::cout << '\n'; sort( a ); for ( const auto &item : a ) std::cout << item << ' '; std::cout << '\n'; reverse( a ); for ( const auto &item : a ) std::cout << item << ' '; std::cout << '\n'; } [/pre2] Вывод программы на консоль [pre2] 3 2 1 sort with requires is called. 1 2 3 reverse with requires is called. 3 2 1 3 2 1 sort without requires is called. 1 2 3 reverse without requires is called. 3 2 1 3 2 1 sort without requires is called. 1 2 3 reverse without requires is called. 3 2 1 [/pre2] Опробовать программу можно с помощью онлайн компилятора по адресу http://melpon.org/wandbox Нужно будет указать опцию компилятора -fconcepts

Сыроежка: Возможно, также имеет смысл объявить обобщенные функции std::find, std::lower_bound, std::upper_bound и std::equal_range. Ниже представлена демонстрационная программа, показывающая использование обобщенной функции lower_bound. [pre2] #include <iostream> #include <functional> #include <vector> #include <set> #include <iterator> #include <algorithm> template <typename Container, typename Key> auto lower_bound( const Container &container, const Key &key ) requires requires() { &Container::lower_bound; } { std::cout << "lower_bound for a const object with requires is called.\n"; return container.lower_bound( key ); } template <typename Container, typename Key> auto lower_bound( Container &container, const Key &key ) requires requires() { &Container::lower_bound; } { std::cout << "lower_bound for a non-const object with requires is called.\n"; return container.lower_bound( key ); } template <typename Container, typename Key> auto lower_bound( const Container &container, const Key &key ) { std::cout << "lower_bound for a const object without requires is called.\n"; return std::lower_bound( std::begin( container ), std::end( container ), key ); } template <typename Container, typename Key > auto lower_bound( Container &container, const Key &key ) { std::cout << "lower_bound for a non-const object without requires is called.\n"; return std::lower_bound( std::begin( container ), std::end( container ), key ); } template <typename Container, typename Key, typename Compare> auto lower_bound( const Container &container, const Key &key, Compare comp ) { std::cout << "lower_bound for a const object without requires is called.\n"; return std::lower_bound( std::begin( container ), std::end( container ), key, comp ); } template <typename Container, typename Key, typename Compare> auto lower_bound( Container &container, const Key &key, Compare comp ) { std::cout << "lower_bound for a non-const object without requires is called.\n"; return std::lower_bound( std::begin( container ), std::end( container ), key, comp ); } int main() { std::set<int> set1 = { 1, 2, 3, 4, 5 }; int value = 4; auto it1 = lower_bound( set1, value ); std::cout << "The position for " << value << " is " << std::distance( std::begin( set1 ), it1 ) << '\n'; const std::set<int> set2 = { 1, 2, 3, 4, 5 }; auto it2 = lower_bound( set2, value ); std::cout << "The position for " << value << " is " << std::distance( std::begin( set2 ), it2 ) << '\n'; std::cout << '\n'; std::vector<int> v1 = { 1, 2, 3, 4, 5 }; auto it3 = lower_bound( v1, value ); std::cout << "The position for " << value << " is " << std::distance( std::begin( v1 ), it3 ) << '\n'; const std::vector<int> v2 = { 1, 2, 3, 4, 5 }; auto it4 = lower_bound( v2, value ); std::cout << "The position for " << value << " is " << std::distance( std::begin( v2 ), it4 ) << '\n'; std::cout << '\n'; std::vector<int> v3 = { 1, 2, 3, 4, 5 }; auto it5 = lower_bound( v3, value, std::less<>() ); std::cout << "The position for " << value << " is " << std::distance( std::begin( v3 ), it5 ) << '\n'; const std::vector<int> v4 = { 1, 2, 3, 4, 5 }; auto it6 = lower_bound( v4, value, std::less<>() ); std::cout << "The position for " << value << " is " << std::distance( std::begin( v4 ), it6 ) << '\n'; std::cout << '\n'; } [/pre2] Вывод программы на консоль [pre2] lower_bound for a non-const object with requires is called. The position for 4 is 3 lower_bound for a const object with requires is called. The position for 4 is 3 lower_bound for a non-const object without requires is called. The position for 4 is 3 lower_bound for a const object without requires is called. The position for 4 is 3 lower_bound for a non-const object without requires is called. The position for 4 is 3 lower_bound for a const object without requires is called. The position for 4 is 3 [/pre2]

Сыроежка: Будет более правильным определить обобщенные функции std::sort и std::reverse таким образом, чтобы они возвращали ссылку на исходный контейнер. Рассмотрите, к примеру, следующий вопрос начинающего программиста на сайте Stackoverflow Checking if two strings are anagram В указанном вопросе требуется проверить, являются ли две строки анаграммами друг друга. Один из подходов решения поставленной задачи - это сортировать строки и сравнить их друг с другом. Написать соответствующую функцию будет очень просто, если обобщенная функция std::sort (это также касается и обобщенной функции std::reverse) будет возвращать ссылку на исходный контейнер. Ниже представлена демонстрационная программа. [pre2] #include <iostream> #include <iomanip> #include <string> #include <iterator> #include <algorithm> template <typename Container> Container & sort( Container &container ) requires requires() { &Container::sort; } { container.sort(); return container; } template <typename Container> Container & sort( Container &container ) { std::sort( std::begin( container ), std::end( container ) ); return container; } bool isAnagrams( std::string s1, std::string s2 ) { return std::size( s1 ) == std::size( s2 ) and sort( s1 ) == sort( s2 ); } int main() { std::cout << "Enter two strings: "; std::string s1, s2; std::cin >> s1 >> s2; std::cout << "The strings " << std::quoted( s1 ) << " and " << std::quoted( s2 ) << " are " << ( isAnagrams( s1, s2 ) ? "" : "not" ) << " anagrams of each other.\n"; } [/pre2] Ее вывод на консоль может выглядеть, к примеру, следующим образом: [pre2] Enter two strings: act tac The strings "act" and "tac" are anagrams of each other.[/pre2]




полная версия страницы