С++11 -- это, конечно, мощная штука. Но для некоторых вещей все же, как и в старые добрые времена, нужно использовать трюкачество. Один из подобных трюков я нашел на StackOverflow, когда мне потребовалось определить сигнатуру лямбда-функции (т.е. выделить тип результирующего значения и тип параметра). Решение подсказано Энтони Уильямсом. Продублирую его здесь, дабы никуда ходить не нужно было. Так же следует обратить внимание на предупреждение о применимости этого подхода:
#include <iostream> template<typename F,typename R> void do_stuff(F& f,R (F::*mf)() const) { (f.*mf)(); } template<typename F,typename R,typename A1> void do_stuff(F& f,R (F::*mf)(A1) const) { (f.*mf)(99); } template<typename F,typename R,typename A1,typename A2> void do_stuff(F& f,R (F::*mf)(A1,A2) const) { (f.*mf)(42,123); } template<typename F> void do_stuff(F f) { do_stuff(f,&F::operator()); } int main() { do_stuff([]{std::cout<<"no args"<<std::endl;}); do_stuff([](int a1){std::cout<<"1 args="<<a1<<std::endl;}); do_stuff([](int a1,int a2){std::cout<<"2 args="<<a1<<","<<a2<<std::endl;}); } |
Предупреждение: данный код не работает с функциональными типами (т.е. с указателями на функции); с классами, в которых более одного operator(); с классами, у которых operator() не константен.
Небольшое пояснение сути этого трюка. Лямбда в C++11 -- это объект какого-то сгенерированного компилятором типа. Компилятор умеет приводить лямбду к std::function, но лямбда -- это не экземпляр std::function. При этом у лямбды есть operator() const, тип которого можно попытаться диагностировать показанным выше способом. Обычно это так. Но, если лямбда определяется с ключевым словом mutable, то у нее будет operator() без const. И показанный выше подход должен быть доработан так, чтобы были варианты do_stuff, принимающие, скажем, не R (F::*mf)(A1,A2) const, а R (F::*mf)(A1,A2):
template<typename F,typename R,typename A1,typename A2> void do_stuff(F& f,R (F::*mf)(A1,A2) const) { (f.*mf)(42,123); } template<typename F,typename R,typename A1,typename A2> void do_stuff(F& f,R (F::*mf)(A1,A2)) { (f.*mf)(24,321); } ... do_stuff([](int a1,int a2){std::cout<<"2 args="<<a1<<","<<a2<<std::endl;}); do_stuff([](int a1,int a2) mutable {std::cout<<"2 args="<<a1<<","<<a2<<std::endl;}); |
При запуске будет получено:
2 args=42,123
2 args=24,321
Комментариев нет:
Отправить комментарий