Информация об изменениях

Сообщение Re: Перегрузка методов с лямбдами от 07.01.2017 17:57

Изменено 08.01.2017 17:48 Кодт

Re: Перегрузка методов с лямбдами
Здравствуйте, Kingofastellarwar, Вы писали:

Можно (взять готовый в C++17 или навелосипедить свой) is_callable и использовать его в SFINAE
  template<class P> auto contains(P&& p) ->
    // если существует и приводится к bool выражение p(t), где t - элемент коллекции
    std::enable_if< std::is_convertible< declspec(p(std::declval<T>())), bool >::value, bool >
  { return std::find_if(std::begin(*this), std::end(*this), std::forward<T>(p)) != std::end(*this); }

  template<class V> auto contains(V&& v) ->
    // если существует и приводится к bool выражение t == v
    std::enable_if< std::is_convertible< declspec(std::declval<T>() == v), bool >::value, bool >
  { return std::find(std::begin(*this), std::end(*this), std::forward<V>(v)) != std::end(*this); }


Но, как уже сказали выше, лучше не создавать, а потом героически разруливать неоднозначность семантики, — а с самого начала завести contains и contains_if.

И кстати, с т.з. английского языка, the_container.contains(value), а не the_container.contain(value).
Предикат — в 3 лице ед.числе.
А внешняя функция-алгоритм — find, find_if — в инфинитиве/императиве.
Re: Перегрузка методов с лямбдами
Здравствуйте, Kingofastellarwar, Вы писали:

Можно (взять готовый в C++17 или навелосипедить свой) is_callable и использовать его в SFINAE
  template<class P> auto contains(P&& p) ->
    // если существует и приводится к bool выражение p(t), где t - элемент коллекции
    std::enable_if< std::is_convertible< decltype(p(std::declval<T>())), bool >::value, bool >::type
  { return std::find_if(std::begin(*this), std::end(*this), std::forward<T>(p)) != std::end(*this); }

  template<class V> auto contains(V&& v) ->
    // если существует и приводится к bool выражение t == v
    std::enable_if< std::is_convertible< decltype(std::declval<T>() == v), bool >::value, bool >::type
  { return std::find(std::begin(*this), std::end(*this), std::forward<V>(v)) != std::end(*this); }


Вот наколбасил эксперимент
http://ideone.com/SQNwIS
  Скрытый текст
#include <iostream>
#include <type_traits>
#include <vector>
#include <algorithm>
using namespace std; // это инициатива от ideone.com, пусть будет.
 
template<class T> struct container {
    vector<T> ts;
    template<class F> auto contains(F&& f) const ->
        typename enable_if< is_convertible< decltype(f(declval<T>())), bool >::value, bool >::type
    {
        cout << "predicate\n";
        return find_if(begin(ts), end(ts), f) != end(ts);
    }
    template<class V> auto contains(V&& v) const ->
        typename enable_if< is_convertible< decltype(declval<T>() == v), bool >::value, bool >::type
    {
        cout << "match\n";
        return find(begin(ts), end(ts), v) != end(ts);
    }
};

// чтобы жизнь мёдом не казалась: а вдруг предикат вернёт не bool, а что попало (здесь - указатель на член)
struct XZ { void xz() {} };
typedef void(XZ::*unspecified_bool)(); 
unspecified_bool unspec(bool v) { return v ? &XZ::xz : (unspecified_bool)0; }

// заодно проверим, можно ли искать по ключу, условно-совместимому с типом элементов
struct ONE {};
unspecified_bool operator == (int x, ONE y) {
    cout << "compare " << x << " to ONE...\n";
    return unspec(x == 1);
}

int main() {
    container<int> d { {0, 3, 1, 2} };
    cout << d.contains([](double x) {
        cout << "examine " << x << "...\n";
        return unspec(x==1); })
    << endl;
    cout << d.contains(ONE()) << endl;
}



Но, как уже сказали выше, лучше не создавать, а потом героически разруливать неоднозначность семантики, — а с самого начала завести contains и contains_if.

И кстати, с т.з. английского языка, the_container.contains(value), а не the_container.contain(value).
Предикат — в 3 лице ед.числе.
А внешняя функция-алгоритм — find, find_if — в инфинитиве/императиве.