Как дифференцировать две лямбда-функции по типу возвращаемого значения? - PullRequest
0 голосов
/ 29 сентября 2019

Я пытаюсь создать перегрузку оператора типа bash для лямбда-функций, в которой вы передаете вектор и в лямбду, которая фильтрует или печатает вектор

Я пытался использовать auto сdecltype, попытался поместить их все в одну и ту же функцию, надеясь, что auto будет знать, когда возвращать void и когда возвращать вектор, но все, что я пытаюсь, либо не компилируется, либо говорит о неоднозначной перегрузке.

Вот код,

#include <iostream>
#include <algorithm>
#include <functional>
#include <type_traits>

using namespace std;

void operator | ( auto& v, auto map ) {
  for( auto x : v )
    map( x );
}

template <typename T>
T operator | ( T& vet, auto map)  {
    cout << "else" << endl;
    T aux;
    for ( auto x : vet) 
        aux.push_back(x);
    return aux;
}

int main () {
    vector<int> v{1,2,3,4,5,6,7,8} ;
     v | []( int x ) { return x % 2 == 0; } | [] ( int x ) { cout << x << endl; };
     v | [] ( int x ) { cout << x << endl; };
    return 0;
}

Вот что происходит:

trabapply3.cc:25:6: error: ambiguous overload for ‘operator|’ (operand types are ‘std::vector<int>’ and ‘main()::<lambda(int)>’)
   25 |    v | [] ( int x ) { cout << x << endl; };

Любые советы?

1 Ответ

1 голос
/ 29 сентября 2019

Используйте std::is_invocable_r / std::invole_result_t.

#include <iostream>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <vector>

template<typename T>
using element_type_t = std::remove_reference_t<decltype(*std::begin(std::declval<T&>()))>;

template <typename T, typename MapFunc, std::enable_if_t<std::is_void_v<std::invoke_result_t<MapFunc, element_type_t<T>>>, std::nullptr_t> = nullptr>
void operator | (const T& v, MapFunc&& map ) {
  for(auto&& x : v )
    map( x );
}

template <typename T, typename MapFunc, std::enable_if_t<std::is_invocable_r_v<element_type_t<T>, MapFunc, element_type_t<T>>, std::nullptr_t> = nullptr>
T operator | (const T& vet, MapFunc&& map)  {
    T aux;
    for (auto&& x : vet) 
        aux.push_back(map(x));
    return aux;
}

int main () {
    std::vector<int> v{1,2,3,4,5,6,7,8} ;
     v | []( int x ) { return x % 2 == 0; } | [] ( int x ) { std::cout << x << std::endl; };
     v | []( int x ) { std::cout << x << std::endl; };
    return 0;
}

https://wandbox.org/permlink/33zSMBubghwEt4EF

Примечание: о element_type_t: часы Введите trait для получения типа элемента std:: массив или массив в стиле C

Кстати, вы не должны писать using namespace std;.

...