Современный C++ позволяет писать довольно лаконично. Например, если есть вот такая структура с функциями-фабриками:
struct factories_t { std::function< dispatcher_unique_ptr_t() > m_disp_factory; std::function< binder_unique_ptr_t() > m_bind_factory; }; |
То можно написать вот такую функцию, которая создает экземпляры данной структуры:
factories_t create_factories( const std::string & name ) { if( "first" == name ) return { []() { return create_first_dispatcher(); }, []() { return create_first_binder(); } }; return { []() { return create_second_dispatcher(); }, []() { return create_second_binder(); } }; } |
К сожалению, в MSVC++ 2013 подобный код работает только, если написанные в create_factories() лямбды не требуют захвата каких-либо переменных. Если же требуют, т.е. если написать лямбду вот так:
return { []() { return create_first_dispatcher(); }, [name]() { return create_first_binder(); } }; |
То при попытке обратиться к ней возникнет исключение с текстом "bad function call" (т.е., похоже, в этом случае лямбда не преобразуется корректно в объект std::function).
Между тем под GCC (4.8.3 и 4.9.0) нормально работают и вариант без захвата контекста, и вариант с захватом контекста.
Пичалька...
Под катом полный самодостаточный код теста для самостоятельной проверки.
#include <functional> #include <iostream> #include <string> #include <memory> // // Basic types // class dispatcher_t { public : virtual ~dispatcher_t() {} virtual void say() = 0; }; typedef std::unique_ptr< dispatcher_t > dispatcher_unique_ptr_t; class binder_t { public : virtual ~binder_t() {} virtual void say() = 0; }; typedef std::unique_ptr< binder_t > binder_unique_ptr_t; // // Basic types implementations. // class first_dispatcher_t : public dispatcher_t { public : virtual void say() override { std::cout << "first dispatcher" << std::endl; } }; class first_binder_t : public binder_t { public : virtual void say() override { std::cout << "first binder" << std::endl; } }; dispatcher_unique_ptr_t create_first_dispatcher() { return dispatcher_unique_ptr_t( new first_dispatcher_t() ); } binder_unique_ptr_t create_first_binder() { return binder_unique_ptr_t( new first_binder_t() ); } class second_dispatcher_t : public dispatcher_t { public : virtual void say() override { std::cout << "second dispatcher" << std::endl; } }; class second_binder_t : public binder_t { public : virtual void say() override { std::cout << "second binder" << std::endl; } }; dispatcher_unique_ptr_t create_second_dispatcher() { return dispatcher_unique_ptr_t( new second_dispatcher_t() ); } binder_unique_ptr_t create_second_binder() { return binder_unique_ptr_t( new second_binder_t() ); } // // Test infrastructure // struct factories_t { std::function< dispatcher_unique_ptr_t() > m_disp_factory; std::function< binder_unique_ptr_t() > m_bind_factory; }; void test( const factories_t & factories ) { std::cout << "creating dispatcher..." << std::flush; auto d = factories.m_disp_factory(); std::cout << "ok" << std::endl; d->say(); std::cout << "creating binder..." << std::flush; auto b = factories.m_bind_factory(); std::cout << "ok" << std::endl; b->say(); } factories_t create_factories( const std::string & name ) { if( "first" == name ) return { []() { return create_first_dispatcher(); }, [name]() { return create_first_binder(); } }; return { []() { return create_second_dispatcher(); }, []() { return create_second_binder(); } }; } int main() { try { test( create_factories( "second" ) ); test( create_factories( "first" ) ); return 0; } catch( const std::exception & x ) { std::cerr << "Exception: " << x.what() << std::endl; } return 2; } |
Комментариев нет:
Отправить комментарий