On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 03.10.13 17:43. Заголовок: false_predicate и true_predicate - полезные типы функциональных объектов


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

Вот как, например, может выглядеть код для ввода целочисленных значений в вектор, объявленный как std::vector<int> v, пока не будет обнаружен конец стандартного входного потока

 
std::vector<int>:: value_type value;

while ( std::cin >> value ) v.push_back( value );


Можно оформить эту операцию в виде отдельной функции, даже сделав ее шаблонной.

 
template <class T>

void fill_container( T &container )
{
typename T::value_type value;

while ( std::cin >> value ) container.push_back( value );
}


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

Но что делать, если задание было изменено, и теперь требуется ввести данные, пока во входном потоке не встретится 0?

Написанная выше функция уже не годится, так как нужно включить дополнительное условие в цикл while. С этим условием тело функции будет выглядеть следующим образом:

 
std::vector<int>:: value_type value;

while ( std::cin >> value && !( value == 0 ) ) v.push_back( value );


Следовательно шаблонную функцию требуется переписать:

 
template <class T>

void fill_container( T &container )
{
typename T::value_type value;

while ( std::cin >> value && !( value == 0 ) ) v.push_back( value );
}


Можно вздохнуть с облегчением? Увы, на этом трудности не закончились! Может потребоваться, что вводить данные нужно будет не до тех пор, пока не встретится 0, а до тех пор, пока не встретится -1!

Придется снова, в третий раз, переписать функцию:

 
template <class T>

void fill_container( T &container )
{
typename T::value_type value;

while ( std::cin >> value && !( value == -1 ) ) v.push_back( value );
}


Итак, при незначительном изменении условия ввода данных нам пришлось три раза переписывать одну и ту же функцию.

Естественно, напрашивается вопрос, а нельзя ли написать одну шаблонную функцию таким образом, чтобы она удовлетворяла всем трем условиям по вводу данных?

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

 
template <class T, class UnaryPredicate>

void fill_container( T &container, UnaryPredicate pred )
{
typename T::value_type value;

while ( std::cin >> value && !pred( value ) ) v.push_back( value );
}


Но что делать с ситуацией, когда вводить данные нужно до тех пор, пока не обнаружится конец входного потока? Ведь в этом случае никакого дополнительного предиката не требуется. Хотелось бы просто вызывать функцию в виде

 
fill_container( v );


Неужели опять придется писать вторую перегруженную функцию, но уже без предиката?

На самом деле можно обойтись всего лишь одной функцией! Для этого достаточно, чтобы второй параметр имел аргумент по умолчанию в виде предиката, который для любого вводимого значения возвращал бы значение false, то есть чтобы ввод не зависел от введенного значения.
Значит нужен предикат или, точнее, два предиката для полноты, которые для любого своего аргумента возвращают значения соответственно false и true.

Увы, таких предикатов нет в стандарте языка C++. А, как мы видим, потребность в них существует.

Вот как можно определить эти предикаты, которые я назвал соответственно false_predicate и true_predicate.

 
template <class ...T> struct false_predicate;

template <class T> struct false_predicate<T>
{
typedef T argument_type;
typedef bool result_type;
constexpr bool operator ()( const T & ) const
{
return ( false );
}

};

template <class T, class U> struct false_predicate<T, U>
{
typedef T first_argument_type;
typedef U second_argument_type;
typedef bool result_type;
constexpr bool operator ()( const T &, const U & ) const
{
return ( false );
}
};

template <class ...T> struct true_predicate;

template <class T> struct true_predicate<T>
{
typedef T argument_type;
typedef bool result_type;
constexpr bool operator ()( const T & ) const
{
return ( true );
}

};

template <class T, class U> struct true_predicate<T, U>
{
typedef T first_argument_type;
typedef U second_argument_type;
typedef bool result_type;
constexpr bool operator ()( const T &, const U & ) const
{
return ( true );
}
};


С помощью одного из этих предикатов, а именно false_predicate нашу шаблонную функцию, универсальную для всех трех условий ввода данных, можно написать следующим образом:

 
template <class T, class UnaryPredicate = false_predicate<typename T::value_type>>
void fill_container( T &container, UnaryPredicate pred = UnaryPredicate() )
{
typename T::value_type value;

while ( std::cin >> value && !pred( value ) ) container.push_back( value );
}



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

 
#include <iostream>
#include <functional>
#include <vector>

template <class ...T> struct false_predicate;

template <class T> struct false_predicate<T>
{
typedef T argument_type;
typedef bool result_type;
constexpr bool operator ()( const T & ) const
{
return ( false );
}

};

template <class T, class U> struct false_predicate<T, U>
{
typedef T first_argument_type;
typedef U second_argument_type;
typedef bool result_type;
constexpr bool operator ()( const T &, const U & ) const
{
return ( false );
}
};

template <class ...T> struct true_predicate;

template <class T> struct true_predicate<T>
{
typedef T argument_type;
typedef bool result_type;
constexpr bool operator ()( const T & ) const
{
return ( true );
}

};

template <class T, class U> struct true_predicate<T, U>
{
typedef T first_argument_type;
typedef U second_argument_type;
typedef bool result_type;
constexpr bool operator ()( const T &, const U & ) const
{
return ( true );
}
};

template <class T, class UnaryPredicate = false_predicate<typename T::value_type>>
void fill_container( T &container, UnaryPredicate pred = UnaryPredicate() )
{
typename T::value_type value;

while ( std::cin >> value && !pred( value ) ) container.push_back( value );
}


int main()
{
std::vector<int> v;

fill_container( v );

for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;

std::cout << std::endl;

v.clear();
fill_container( v, std::bind2nd( std::equal_to<int>(), -1 ) );

for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;

std::cout << std::endl;

v.clear();
fill_container( v, std::bind2nd( std::equal_to<int>(), 0 ) );

for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;

return 0;
}


Этот код успешно компилируется, если использовать компилятор GCC. Вы можете проверить это с помощью онлайнового компилятора по ссылке
www.ideone.com

Если в этом онлайновом компиляторе задать входной поток как

1 2 3 4 5 6 7 8 9 0 -1

то выходной результат работы программы будет следующим:

1 2 3 4 5 6 7 8 9 0 -1

1 2 3 4 5 6 7 8 9 0

1 2 3 4 5 6 7 8 9

То есть каждый вывод соответствует своему условию при вводе данных.

Думаю, что присутствие этих предикатов, false_predicate и true_predicate, в стандарте языка C++ не было бы лишним. :)

Спасибо: 0 
ПрофильЦитата Ответить
Новых ответов нет


Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 10
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет