2016-02-14 3 views
9

Я играл с «перегрузкой» лямбда, как представлено here, и быстро дошел до того места, где мне было бы удобно создавать специализированные закрылки лямбда. Так что я был первым методом проб и error'ing немного, с моим самым многообещающим испытание бытьC++ специализируется на лямбда для определенного типа

auto call_for_vector = [] template<typename T> (std::vector<T>) {}; 

Однако позже взгляд на cppreference показал, что ни это, ни подобные конструкции, как представляется, допускается стандартом.

В чем причина такой специализации не поддерживается?

Я знаю, что это можно получить с помощью SFINAE, но тогда оно менее читаемо, труднее писать и подвержено большей подверженности ошибкам. Конечно, можно также Simpy написать класс с соответствующим operator(), но это Су C++ 03 :-)



Какая польза была бы для такого синтаксиса ?:

Одним из примеров, это позволило бы легко лямбда «перегрузки», как показано в следующем коде

template <class F1, class F2> 
struct overload_set : F1, F2 
{ 
    overload_set(F1 x1, F2 x2) : F1(x1), F2(x2) {} 
    using F1::operator(); 
    using F2::operator(); 
}; 

template <class F1, class F2> 
overload_set<F1,F2> overload(F1 x1, F2 x2) 
{ 
    return overload_set<F1,F2>(x1,x2); 
} 

auto f = overload(
     [](auto&& x){ std::cout<<"call by default"<<std::endl;}, 
     [] template<typename T>(std::vector<T>){std::cout<<"call for vector"<<std::endl;} 
     ); 

можно получить такое поведение, например, используя базу SFINAE по технике в this answer, но опять же ... это отстой.

Есть ли у SFINAE легкое обходное решение для получения конкретных перегрузок?

+0

ну, я думаю, вы являетесь familliar с std :: function, что является способом работы с прочными функциями. Я думаю, что лямбды неустойчивы в том смысле, что стандарт не хотел бы, чтобы вы их хранили, равно –

+0

@David Haim: вышеупомянутое не работает с 'std :: function', так как ему нужна определенная подпись. – davidhigh

+0

вы можете templatetize std :: function, 'template std :: function ' вы не можете сделать это с помощью lambda –

ответ

2

Этот тип кодировки может показаться излишним сначала, но есть некоторые приятные свойства, которыми мы можем воспользоваться. Что касается сообщения, которое вы упомянули, я планировал часть 2, где я бы продемонстрировал опрятный способ , проверяющий, имеет ли тип определенный член (функция или данные). Предположим, вы хотите проверить функцию члена serialize; вместо использования сложных механизмов, я обнаружил, что это становится так легко, как:

auto hs = overload( 
    [ ](auto&& x) -> decltype(x.serialize(2), std::true_type{}) { 
     return{}; },  // ^^ this guy ^^ 
    [ ](...) -> std::false_type { return {}; }); 

demo

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

auto do_something = overload( 
    [ ]<class X>(shared_ptr<X> x) -> decltype(x.serialize(2), std::true_type{}) { 
     /*do something specific for shared ptrs of X */ return{}; },  
    [ ]<class X>(X& x) -> decltype(x.serialize(2), std::true_type{}) { 
     /*do a generic operation for other types that have serialize*/return{}; },  
    [ ](...) -> std::false_type { /*do nothing*/ return {}; }); 
+2

ah , да, поэтому sfinae, но современный (и более короткий) способ ... – davidhigh

+0

не могли бы вы добавить ссылку на свой другой ответ? Тогда я бы дал ему крючок, а затем давайте закроем эту тему на большом торжестве как дубликат. – davidhigh

+0

@ davidhigh У меня нет другого ответа, я просто сделал аналогичный q –

Смежные вопросы