А generic-и так могут?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 29.05.05 20:25
Оценка: 5 (1)
Уважаемые коллеги!

Одним из самых полезных для меня качеств языка C++ является, имхо, удобство при сопровождении и расширении ранее написанного кода. Этому способствуют такие возможности, как препроцессор, перегрузка методов и функций, аргументы по умолчанию и шаблоны. Вот как раз о шаблонах для упрощения сопровождения кода и пойдет речь.

Не хотелось бы превращать эту тему в очередной холивар по поводу C++ vs C# vs Java. Просто я на днях с помощью шаблонов расширил функциональность одного из модулей. При этом не потребовалась модификация кода, который работал с этим модулем ранее. Ниже я привожу примененное мной решение на C++.

Я хотел бы узнать, можно ли подобные вещи вытворять с помощью generic-ов в C# и/или Java. И если можно, насколько это выглядит проще/читабельнее и/или эффективнее.



Задача в том, что есть два механизма доставки получателям сообщений. Один синхронный (под названием mbapi), второй -- асинхронный (под названием SObjectizer). Был создан модуль, позволяющий строить преобразования синхронных сообщений mbapi в асинхронные сообщения SObjectizer-а. Для этого, каждому сообщению mbapi нужно было сопоставить специальный объект-почтальон (postman), который преобразовывает экземпляр асинхронного mbapi-сообщения, в экземпляр асинхронного сообщения и производит отсылку SObjectizer-сообщения получателю.

Для удобства использования всей этой кухни было сделано несколько вспомогательных шаблонных класса. Один из них, so_postman_templ_t был базовым шаблоном для почтальона. Он требовал, чтобы его параметризовали типом сообщения, у которого есть конструктор с тремя аргументами:
Sobj_type(
    // Адрес получателя сообщения.
    To_type * to,
    // Само сообщение.
    Mbapi_type * msg,
    // Адрес отправителя сообщения (обратный адрес).
    Reply_to_type * reply_to );


За время работы с so_postman_templ_t было написано много кода. Часть сообщений, которыми параметризовался so_postman_templ_t были созданы с использованием другого шаблона (so_msg_templ_t -- специальный шаблон для генерации SObjectizer-сообщений из mbapi-сообщений, so_msg_templ_t так же был подобным прозрачным образом модифицирован), но была и часть, которая была специально создана в расчете на первоначальную спецификацию.

Важно отметить, что сперва требовалось оперировать всего тремя параметрами сообщения: адресами отправителя и получателя, и самим сообщением. Но в один прекрасный момент, когда по старой схеме работало уже много чего, возникла необходимость сопоставить сообщению дополнительную, расширенную информацию. Т.е., потребовалось поддержать SObjectizer-сообщения, конструктор которых имеет вид:
Sobj_type(
    To_type * to,
    Mbapi_type * msg,
    Reply_to_type * reply_to,
    std::auto_ptr< mbapi_3::extended_info_t > extended_info );

т.е., в зависимости от того, какие параметры шаблона использованы для инстанцирования so_postman_templ_t, код so_postman_templ_t должен создавать объекты типа Sobj_type используя либо конструктор с тремя параметрами, либо конструктор с четырьмя параметрами. Причем, в коде so_postman_templ_t нельзя было написать простой if и использовать в разных его ветках разные вызовы конструкторов. Ведь тогда компилятор и линкер требовали бы наличия у типа Sobj_type сразу обоих конструкторов. А вся задача состояла в том, чтобы новая версия so_postman_templ_t умела работать со старыми типами, у которых конструкторы всего с тремя параметрами.

У меня на C++ шаблонах получилось приведенное ниже решение. Хочу сделать два отступления. Во-первых, требовалось обеспечить совместимость с VC++ 6.0, в котором нет поддержки частичной специализации. Из-за этого пришлось ввести дополнительные типы: sender_params_t, no_extended_info_support_sender_t, extended_info_support_sender_t, sender_selector_t. Если бы можно было применить частную специализацию, то можно было обойтись всего одним типом и его частичной специализацией. И решение бы сильно сократилось в объеме.
Во-вторых, я понимаю, что ошибка была допущена в самом начале, когда было решено передавать в конструктор Sobj_type всю имеющуюся информацию в виде отдельных параметров. Проблем бы не было, если бы передавался всего один аргумент -- некая структура, из которой можно было бы извлечь все. Да, такая ошибка была мной допущена. Но, она была выявлена после двух лет успешной эксплуатации, когда начали меняться требования к имеющемуся механизму. И вот в таких неприятных, но реальных, условиях шаблоны C++ позволили обеспечить работоспособность уже написанного кода.

Вот, собственно, само решение:
//
// extended_info_t
//

/*!
    \since v.3.3.0
    \brief Расширеная информация об MBAPI-сообщении, которая доступна
        для получателя MBAPI-сообщения.

    Большинству получателей MBAPI-сообщений необходимо всего три значения:
    пункт назначения сообщения, само сообщение и его обратный адрес.
    Но в версии 3.3.0 получателю предоставляется так же возможность получить
    историю ремаршрутизаций сообщения. В следующих версиях получатель может
    захотеть получать еще какую-то информацию о сообщении. Для того, чтобы
    не модифицировать для этого шаблон so_templ_postman_t предлагается
    всю дополнительную информацию передавать получателю в виде структуры
    extended_info_t, которая будет расширятся дополнительными атрибутами по
    мере надобности.
*/
struct    extended_info_t
    {
        //! История ремаршрутизации сообщений.
        std::auto_ptr< rerouting_history_t >    m_rerouting_history;

        //! Инициализирующий конструктор.
        /*!
            Самостоятельно извлекает всю информацию из delivery_info_t.
        */
        extended_info_t( const delivery_info_t & info )
            :    m_rerouting_history( info.rerouting_history() ?
                    new rerouting_history_t( *info.rerouting_history() ) : 0 )
            {}
        ~extended_info_t()
            {}
        
        /*! \name Методы getter-ы.
            \{ */
        const rerouting_history_t *
        rerouting_history() const { return m_rerouting_history.get(); }
        /*! \} */
    };

namespace impl
{

//
// sender_params_t
//

/*!
    \since v.3.3.0
    \brief Вспомогательная обертка для параметров доставки MBAPI-сообщения
        в виде SObjectizer сообщения.

    Необходима, главным образом, для того, чтобы сделать вспомогательные
    классы no_extended_info_support_sender_t и extended_info_support_sender_t
    не шаблонными -- это необходимо для поддержки C++ компилятров, в которых
    нет частичной специализации шаблонов.
*/
template<
        class Mbapi_type,
        class Sobj_type,
        class To_type,    
        class Reply_to_type >
struct    sender_params_t
    {
        /*! \name Псевдонимы для параметров шаблона.
            \{ */
        typedef Mbapi_type    mbapi_type_t;
        typedef Sobj_type    sobj_type_t;
        typedef To_type    to_type_t;
        typedef Reply_to_type    reply_to_type_t;
        /*! \} */

        //! Исходные параметры MBAPI-сообщения.
        const delivery_info_t &    m_info;

        //! Инициализирующий конструктор.
        sender_params_t( const delivery_info_t & info )
            :    m_info( info )
            {}

        //! Доступ к параметрам MBAPI-сообщения.
        const delivery_info_t &
        info() const { return m_info; }
    };

//
// no_extended_info_support_sender_t
//

/*!
    \since v.3.3.0
    \brief Генератор SObjectizer-сообщения, для случая, когда конструктор
        сообщения получает всего три параметра.
*/
struct    no_extended_info_support_sender_t
    {
        //! Шаблонный метод для генерации SObjectizer-сообщения.
        /*!
            \note В качестве параметра шаблона ожидается sender_params_t.
        */
        template< class Params >
        void
        send(
            //! Имя владельца сообщения.
            const std::string & owner_name,
            //! Имя SObjectizer-сообщения.
            const std::string & msg_name,
            //! Все доступные параметры MBAPI-сообщения.
            const Params & p ) const
            {
                // Для защиты от исключений при выделении памяти.
                std::auto_ptr< Params::to_type_t > to(
                        dynamic_cast< typename Params::to_type_t * >(
                                p.info().to().clone() ) );
                std::auto_ptr< Params::mbapi_type_t > msg(
                        dynamic_cast< typename Params::mbapi_type_t * >(
                                p.info().msg().clone() ) );
                std::auto_ptr< Params::reply_to_type_t > reply_to(
                        dynamic_cast< typename Params::reply_to_type_t * >(
                                p.info().reply_to().clone() ) );

                so_4::api::send_msg_safely( owner_name, msg_name,
                        new typename Params::sobj_type_t(
                                to.release(),
                                msg.release(),
                                reply_to.release() ),
                        "", p.info().delay() );
            }
    };

//
// extended_info_support_sender_t
//

/*!
    \since v.3.3.0
    \brief Генератор SObjectizer-сообщения, для случая, когда конструктор
        сообщения получает четвертым параметром rerouting_history.
*/
struct    extended_info_support_sender_t
    {
        //! Шаблонный метод для генерации SObjectizer-сообщения.
        /*!
            \note В качестве параметра шаблона ожидается sender_params_t.
        */
        template< class Params >
        void
        send(
            //! Имя владельца сообщения.
            const std::string & owner_name,
            //! Имя SObjectizer-сообщения.
            const std::string & msg_name,
            //! Все доступные параметры MBAPI-сообщения.
            const Params & p ) const
            {
                // Для защиты от исключений при выделении памяти.
                std::auto_ptr< Params::to_type_t > to(
                        dynamic_cast< typename Params::to_type_t * >(
                                p.info().to().clone() ) );
                std::auto_ptr< Params::mbapi_type_t > msg(
                        dynamic_cast< typename Params::mbapi_type_t * >(
                                p.info().msg().clone() ) );
                std::auto_ptr< Params::reply_to_type_t > reply_to(
                        dynamic_cast< typename Params::reply_to_type_t * >(
                                p.info().reply_to().clone() ) );
                std::auto_ptr< extended_info_t > extended(
                        new extended_info_t( p.info() ) );

                so_4::api::send_msg_safely( owner_name, msg_name,
                        new typename Params::sobj_type_t(
                                to, msg, reply_to, extended ),
                        "", p.info().delay() );
            }
    };

//
// sender_selector_t
//

/*!
    \since v.3.3.0
    \brief Вспомогательный класс для выбора одного из sender-ов.

    Данная версия одновременно является специализацией для случая,
    когда Extended_info_supported == false.
*/
template< bool Extended_info_supported >
struct    sender_selector_t
    {
        typedef no_extended_info_support_sender_t    sender_type_t;
    };

/*!
    \since v.3.3.0

    Специализация sender_selector_t для случая, когда
    Extended_info_suppored == true.
*/
template<>
struct    sender_selector_t< true >
    {
        typedef extended_info_support_sender_t    sender_type_t;
    };

} /* namespace impl */

//
// so_postman_templ_t
//

//! Реализация интерфейса %postman_t в виде шаблона.
/*!

    \par Версии, предшествующие 3.3.0
    Предназначен для генерации SObjectizer-сообщений,
    которые имеют конструктор следующего вида:
\code
Sobj_type(
    To_type * to,
    Mbapi_type * msg,
    Reply_to_type * reply_to );
\endcode

    Например:
\code
struct    msg_receiver_ack_t
{
    std::auto_ptr< mbapi_3::dest_t > m_to;
    std::auto_ptr< mbapi_3::sms::receive_ack_t > m_msg;
    std::auto_ptr< mbapi_3::dest_t > m_reply_to;

    msg_receiver_ack_t() {}
    msg_receiver_ack_t(
        mbapi_3::dest_t * to,
        mbapi_3::sms::receive_ack_t * msg,
        mbapi_3::dest_t * reply_to )
        :    m_to( to )
        ,    m_msg( msg )
        ,    m_reply_to( reply_to )
        {
        }
};

so_postman_templ_t<
        mbapi_3::sms::receive_ack_t,
        msg_receive_ack_t >
    receive_ack_postman(
        "some_agent_name",
        "msg_receive_ack" );
\endcode

    \par Начиная с версии 3.3.0 поддерживаются SObjectizer-сообщения,
    конструктор который имеет следующий вид:
\code
Sobj_type(
    std::auto_ptr< To_type > to,
    std::auto_ptr< Mbapi_type > msg,
    std::auto_ptr< Reply_to_type > reply_to,
    std::auto_ptr< mbapi_3::extended_info_t > extended_info );
\endcode
*/
template<
    // Тип MBAPI-сообщения.
    class    Mbapi_type,
    // Тип SObjectizer-сообщения.
    class    Sobj_type,
    // Тип адреса получателя сообщения.
    class To_type = mbapi_3::dest_t,
    // Тип адреса отправителя сообщения.
    class    Reply_to_type = mbapi_3::dest_t,
    // Поддерживается ли получателем расширенная информация?
    bool Extended_info_supported = false >
class    so_postman_templ_t :
    public postman_t
    {
    private :
        //! Имя агента-владельца сообщения.
        const std::string    m_owner_agent;
        //! Имя сообщения, которое нужно отослать.
        const std::string    m_msg_name;

        //! Объект, который реально будет осущетвлять доставку сообщения.
        const typename impl::sender_selector_t<
                        Extended_info_supported >::sender_type_t
                m_sender;

    public :
        inline
        so_postman_templ_t(
            //! Имя агента-владельца сообщения.
            const std::string & owner_agent,
            //! Имя сообщения, которое нужно отослать.
            const std::string & msg_name )
            :    m_owner_agent( owner_agent )
            ,    m_msg_name( msg_name )
            {}

        virtual ~so_postman_templ_t()
            {}

        virtual void
        deliver(
            const mbapi_3::router::delivery_info_t & info )
            {
                impl::sender_params_t<
                                Mbapi_type, Sobj_type, To_type, Reply_to_type >
                        params( info );
                m_sender.send( m_owner_agent, m_msg_name, params );
            }
    };

} /* namespace router */

} /* namespace mbapi_3 */


Т.е., фокус в том, что если Extended_info_supported равен false (по умолчанию), то so_postman_templ_t::m_sender имеет тип impl::no_extended_info_support_sender_t и для инстанцирования SObjectizer-сообщения используется конструктор с тремя параметрами. В противном случае m_sender имеет тип impl::extended_info_support_sender_t и для инстанцирования SObjectizer сообщения используется контруктор с четырьмя параметрами. Причем осуществляется все это в compile-time.

Получается, что в старом коде и в том новом коде, в котором не требуется extended_info_t, шаблон so_postman_templ_t применяется без последного параметра Extended_info_supported (принимается значение false). Если же новому коду нужно использовать extended_info_t, то при инстанцировании so_postman_templ_t указывается true в качестве параметра Extended_info_supported.

Важным достоинством шаблонов C++ здесь является то, что если extended_info_t получателю сообщения не нужен, то при генерации SObjectizer сообщения он даже не создается.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: А generic-и так могут?
От: _FRED_ Черногория
Дата: 30.05.05 08:29
Оценка:
Здравствуйте, eao197, Вы писали:

E>Уважаемые коллеги!


E> Одним из самых полезных для меня качеств языка C++ является, имхо, удобство при сопровождении и расширении ранее написанного кода. Этому способствуют такие возможности, как препроцессор, перегрузка методов и функций, аргументы по умолчанию и шаблоны. Вот как раз о шаблонах для упрощения сопровождения кода и пойдет речь.


E> Не хотелось бы превращать эту тему в очередной холивар по поводу C++ vs C# vs Java. Просто я на днях с помощью шаблонов расширил функциональность одного из модулей. При этом не потребовалась модификация кода, который работал с этим модулем ранее. Ниже я привожу примененное мной решение на C++.


[...skipped...]


Правильно я догадался, что при появлении необходимости передавать _иногда_ дополнительную информацию, пришлось не только расширить so_postman_templ_t, но и добавить несколько типов: no_extended_info_support_sender_t, extended_info_support_sender_t, template< bool Extended_info_supported >
struct sender_selector_t, template<> struct sender_selector_t< true >?
Пытаюсь вот представить себе, что было и что стало.
under « — Tango In Space»,
... << RSDN@Home 1.1.4 beta 7 rev. 461>>
Help will always be given at Hogwarts to those who ask for it.
Re[2]: А generic-и так могут?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 30.05.05 08:46
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, eao197, Вы писали:


E>>Уважаемые коллеги!


E>> Одним из самых полезных для меня качеств языка C++ является, имхо, удобство при сопровождении и расширении ранее написанного кода. Этому способствуют такие возможности, как препроцессор, перегрузка методов и функций, аргументы по умолчанию и шаблоны. Вот как раз о шаблонах для упрощения сопровождения кода и пойдет речь.


E>> Не хотелось бы превращать эту тему в очередной холивар по поводу C++ vs C# vs Java. Просто я на днях с помощью шаблонов расширил функциональность одного из модулей. При этом не потребовалась модификация кода, который работал с этим модулем ранее. Ниже я привожу примененное мной решение на C++.


_FR>[...skipped...]


_FR>

_FR>Правильно я догадался, что при появлении необходимости передавать _иногда_ дополнительную информацию, пришлось не только расширить so_postman_templ_t, но и добавить несколько типов: no_extended_info_support_sender_t, extended_info_support_sender_t, template< bool Extended_info_supported >
_FR>struct sender_selector_t, template<> struct sender_selector_t< true >?
_FR>Пытаюсь вот представить себе, что было и что стало.

Да, правильно, эти типы пришлось добавить (вообще, все что было добавлено, помечено в комментариях как \since v.3.3.0)
Предыдущая реализация so_postman_templ_t имела вид:
template<
    // Тип MBAPI-сообщения.
    class    Mbapi_type,
    // Тип SObjectizer-сообщения.
    class    Sobj_type,
    // Тип адреса получателя сообщения.
    class To_type = mbapi_3::dest_t,
    // Тип адреса отправителя сообщения.
    class    Reply_to_type = mbapi_3::dest_t >
class    so_postman_templ_t :
    public postman_t
{
    private :
        //! Имя агента-владельца сообщения.
        const std::string    m_owner_agent;
        //! Имя сообщения, которое нужно отослать.
        const std::string    m_msg_name;

    public :
        inline
        so_postman_templ_t(
            //! Имя агента-владельца сообщения.
            const std::string & owner_agent,
            //! Имя сообщения, которое нужно отослать.
            const std::string & msg_name )
            :
                m_owner_agent( owner_agent ),
                m_msg_name( msg_name )
        {
        }

        virtual ~so_postman_templ_t()
        {
        }

        inline
        virtual void
        deliver(
            const mbapi_3::dest_t & to,
            const mbapi_3::msg_t & msg,
            const mbapi_3::dest_t & reply_to,
            unsigned int delay )
        {
            so_4::rt::msg_auto_ptr_t< Sobj_type >
                msg_to_send( new Sobj_type(
                    dynamic_cast< To_type * >( to.clone() ),
                    dynamic_cast< Mbapi_type * >( msg.clone() ),
                    dynamic_cast< Reply_to_type * >( reply_to.clone() ) )
                );

            msg_to_send.send( m_owner_agent, m_msg_name, "",
                delay );
        }
};
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: А generic-и так могут?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 31.05.05 16:02
Оценка: +7
Все это здорово, но ради единственно энтузиазма продираться сквозь килобайты кода имхо вряд ли кто станет. Если ты хочешь получить ответ, думаю стоит попытаться вырпазить вопрос ввиде десятка другого строк.
... << RSDN@Home 1.1.4 beta 7 rev. 457>>
AVK Blog
Re[2]: А generic-и так могут? (сокращенный вариант кода)
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 31.05.05 16:34
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Все это здорово, но ради единственно энтузиазма продираться сквозь килобайты кода имхо вряд ли кто станет. Если ты хочешь получить ответ, думаю стоит попытаться вырпазить вопрос ввиде десятка другого строк.


Попробуем.
Итак, был класс:
template< class Mbapi_type, class Sobj_type, class To_type = mbapi_3::dest_t, class Reply_to_type = mbapi_3::dest_t >
class    so_postman_templ_t :
    public postman_t
{
    private :
                ......
                
        inline
        virtual void
        deliver(
            const mbapi_3::dest_t & to,
            const mbapi_3::msg_t & msg,
            const mbapi_3::dest_t & reply_to,
            unsigned int delay )
        {
            so_4::rt::msg_auto_ptr_t< Sobj_type >
                msg_to_send( new Sobj_type(
                    dynamic_cast< To_type * >( to.clone() ),
                    dynamic_cast< Mbapi_type * >( msg.clone() ),
                    dynamic_cast< Reply_to_type * >( reply_to.clone() ) )
                );

            msg_to_send.send( m_owner_agent, m_msg_name, "",
                delay );
        }
};


Важно то, что метод so_postman_templ_t::deliver вызывал у типа Sobj_type конструктор с тремя параметрами. Который использовался, например, так:
struct    some_message_t { some_message_t( dest_type_t * to, source_message_t * msg, dest_type_t * reply_to ) {...} ... };

new so_postman_templ_t< source_message_t, some_message_t, dest_type_t, dest_type_t >( some_agent, some_message );


Со временем пришлось добавить в некоторых случаях поддержку дополнительной информации, для чего у типов Sobj_type (которые хотели эту дополнительную информацию получить) должен быть конструктор с дополнительным аргументом:
struct another_message_t {
    another_message_t( dest_type_t * to, source_message_t * msg, dest_type_t * reply_to,
        std::auto_ptr< extended_info_t > ) {...}
        ...
};


При этом требовалось чтобы so_postman_templ_t можно было параметризовать как типом, в конструктор которого принимает три агрумента, так и типом, который принимает четыре аргумента:
new so_postman_templ_t< source_message_t, some_message_t, dest_type_t, dest_type_t >( some_agent, some_message )
new so_postman_templ_t< source_message_t, another_message_t, dest_type_t, dest_type_t, true >( some_agent, another_message );


При этом нельзя было в коде so_postman_templ_t написать что-то вроде:
template<
    class Mbapi_type, class Sobj_type, class To_type = mbapi_3::dest_t, class Reply_to_type = mbapi_3::dest_t,
    bool Extended_info_supported = false >
class    so_postman_templ_t :
    public postman_t
{
    private :
                ......
                
        inline
        virtual void
        deliver(
            const mbapi_3::dest_t & to,
            const mbapi_3::msg_t & msg,
            const mbapi_3::dest_t & reply_to,
            unsigned int delay )
        {
                    if( Extended_info_supported )
                        new Sobj_type( /* четыре аргумента */ );
                    else
                        new Sobj_type( /* три аргумента */ );
                        
                    ...
        }
};


Поскольку мне нужно было поддерживать Visual C++, в котором нет частичной специализации, то пришлось сделать сложное решение с несколькими вспомогательными типами:
namespace impl
{

template<
        class Mbapi_type,
        class Sobj_type,
        class To_type,    
        class Reply_to_type >
struct    sender_params_t
    {
        typedef Mbapi_type    mbapi_type_t;
        typedef Sobj_type    sobj_type_t;
        typedef To_type    to_type_t;
        typedef Reply_to_type    reply_to_type_t;
                ...
    };

struct    no_extended_info_support_sender_t
    {
        template< class Params >
        void
        send(
            const std::string & owner_name,
            const std::string & msg_name,
            const Params & p ) const
            {
                            /* Фактически здесь вызывается: */
                            new Sobj_type( /* три параметра */ );
                            ...
            }
    };

struct    extended_info_support_sender_t
    {
        template< class Params >
        void
        send(
            const std::string & owner_name,
            const std::string & msg_name,
            const Params & p ) const
            {
                            /* Фактически здесь вызывается: */
                            new Sobj_type( /* четыре параметра */ );
                            ...
            }
    };

template< bool Extended_info_supported >
struct    sender_selector_t
    {
        typedef no_extended_info_support_sender_t    sender_type_t;
    };

template<>
struct    sender_selector_t< true >
    {
        typedef extended_info_support_sender_t    sender_type_t;
    };

} /* namespace impl */

template<
    class    Mbapi_type,
    class    Sobj_type,
    class To_type = mbapi_3::dest_t,
    class    Reply_to_type = mbapi_3::dest_t,
    bool Extended_info_supported = false >
class    so_postman_templ_t :
    public postman_t
    {
    private :
                /* Вот здесь на этапе компиляции определяется, будет ли вызываться
                    конструктор с тремя параметрами или конструктор с четырьмя параметрами */
        const typename impl::sender_selector_t<
                        Extended_info_supported >::sender_type_t
                m_sender;
                ...
    public :
        virtual void
        deliver(
            const mbapi_3::router::delivery_info_t & info )
            {
                impl::sender_params_t<
                                Mbapi_type, Sobj_type, To_type, Reply_to_type >
                        params( info );
                m_sender.send( m_owner_agent, m_msg_name, params );
            }
    };


Если бы можно было забить на Visual C++ 6.0, то нужно было бы всего лишь сделать частную специализацию so_postman_templ_t для случая, когда Extended_info_supported == true.

А воопрос вообще занимает одну строку: чтобы потребовалось сделать для повторения такого фокуса в C# и/или Java?

PS
Здесь приведен псевдокод. Реальный код и более подробная постановка задачи изложена в исходном посте.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: А generic-и так могут?
От: Павел Кузнецов  
Дата: 31.05.05 22:57
Оценка: 12 (1)
eao197,

> Для удобства использования всей этой кухни было сделано несколько вспомогательных шаблонных класса. Один из них, so_postman_templ_t был базовым шаблоном для почтальона. Он требовал, чтобы его параметризовали типом сообщения, у которого есть конструктор с тремя аргументами:

>
> Sobj_type(
>     // Адрес получателя сообщения.
>     To_type * to,
>     // Само сообщение.
>     Mbapi_type * msg,
>     // Адрес отправителя сообщения (обратный адрес).
>     Reply_to_type * reply_to );
>


Тпру, дальше дорогу не сделали: generics не умеют "сами" создавать объекты классов с конструкторами, имеющими параметры, поэтому с использованием generics исходный код выглядел бы как-нибудь очень по-другому.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: А generic-и так могут?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 01.06.05 04:33
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>eao197,


>> Для удобства использования всей этой кухни было сделано несколько вспомогательных шаблонных класса. Один из них, so_postman_templ_t был базовым шаблоном для почтальона. Он требовал, чтобы его параметризовали типом сообщения, у которого есть конструктор с тремя аргументами:

>>
>> Sobj_type(
>>     // Адрес получателя сообщения.
>>     To_type * to,
>>     // Само сообщение.
>>     Mbapi_type * msg,
>>     // Адрес отправителя сообщения (обратный адрес).
>>     Reply_to_type * reply_to );
>>


ПК>Тпру, дальше дорогу не сделали: generics не умеют "сами" создавать объекты классов с конструкторами, имеющими параметры, поэтому с использованием generics исходный код выглядел бы как-нибудь очень по-другому.


Т.е. при использовании generic-ов пришлось бы, например, чтобы в типе SObj_type был статический метод-фабрика. И создание бы объекта выглядело как-то так:
Sobj_type * instance = Sobj_type::create_instance( to, msg, reply_to );


Такая штука с generic-ами возможна?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: А generic-и так могут?
От: Павел Кузнецов  
Дата: 01.06.05 15:51
Оценка: 35 (3)
eao197,

> ПК> Тпру, дальше дорогу не сделали: generics не умеют "сами" создавать объекты классов с конструкторами, имеющими параметры, поэтому с использованием generics исходный код выглядел бы как-нибудь очень по-другому.


> Т.е. при использовании generic-ов пришлось бы, например, чтобы в типе SObj_type был статический метод-фабрика. И создание бы объекта выглядело как-то так:

>
> Sobj_type * instance = Sobj_type::create_instance( to, msg, reply_to );
>

> Такая штука с generic-ами возможна?

Так тоже не получится: generics умеют вызывать только (виртуальные) методы интерфейсов. Вот мои мучения вокруг этого: http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05
Вот ссылка на мнение Брюса Эккеля по этому поводу: http://rsdn.ru/Forum/Message.aspx?mid=989922
Автор: Павел Кузнецов
Дата: 17.01.05
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[4]: А generic-и так могут?
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 01.06.05 21:30
Оценка: +3
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Так тоже не получится: generics умеют вызывать только (виртуальные) методы интерфейсов. Вот мои мучения вокруг этого: http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05
Вот ссылка на мнение Брюса Эккеля по этому поводу: http://rsdn.ru/Forum/Message.aspx?mid=989922
Автор: Павел Кузнецов
Дата: 17.01.05


Мда. Место заменителя C++ остаётся вакантным.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: А generic-и так могут?
От: McSeem2 США http://www.antigrain.com
Дата: 02.06.05 02:49
Оценка: 38 (3) +2 :))) :))) :))) :)
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Так тоже не получится: generics умеют вызывать только (виртуальные) методы интерфейсов. Вот мои мучения вокруг этого: http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05
Вот ссылка на мнение Брюса Эккеля по этому поводу: http://rsdn.ru/Forum/Message.aspx?mid=989922
Автор: Павел Кузнецов
Дата: 17.01.05


Bottom line:
Генерики, что в C#, что в Java — это чисто так, гламурненько. А шаблоны в C++ — это ГОТИЧНО!
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re[4]: А generic-и так могут?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.06.05 07:02
Оценка: +1
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>eao197,


>> Т.е. при использовании generic-ов пришлось бы, например, чтобы в типе SObj_type был статический метод-фабрика. И создание бы объекта выглядело как-то так:

>>
>> Sobj_type * instance = Sobj_type::create_instance( to, msg, reply_to );
>>

>> Такая штука с generic-ами возможна?

ПК>Так тоже не получится: generics умеют вызывать только (виртуальные) методы интерфейсов. Вот мои мучения вокруг этого: http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05


Имхо, мне показалось, что там речь шла немного о другом -- о том, насколько дорого достичь приемлимой производительности с использованием generic-ов в C#. Мне же интересен немного другой аспект generic-ов, я бы сказал, выразительная мошь. Т.е. меня интересует, насколько геморройно (или наоборот) с помощью generic-ов решаются задачи, которые я решал на шаблонах C++ почти без проблем.

Нужно, похоже, самому разобраться с generic-ами в Java (поскольку этот язык я когда-то знал), а затем и как-то с C# (только его я совсем не знаю). И тогда, может быть, что-то проясниться.

Пока я подумал, что на generic-ах можно было бы сделать что-то, похожее на этот вариант на C++:
template< class Mbapi_type, class Sobj_type, class Sobj_type_factory, class To_type, class Reply_to_type >
class    so_postman_templ_t
{
private :
    Sobj_type_factory m_factory;
    ...
public :
    so_postman_templ_t( Sobj_type_factory factory, ... ) : m_factory( factory ), ... { ... }
    
    void deliver(...)
        {
            Sobj_type * message = Sobj_type_factory.create(...);
            ...
        }
};


Да только засомневался что-то, что такое возможно, поскольку Sobj_type_factory так же должен быть шаблоном (ведь он же должен как-то связываться с параметрами Mbapi_type, Sobj_type, To_type, Reply_to_type).
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: А generic-и так могут?
От: alexeiz  
Дата: 02.06.05 08:44
Оценка: +5
"Павел Кузнецов" <5834@users.rsdn.ru> wrote in message
news:1201223@news.rsdn.ru
> Так тоже не получится: generics умеют вызывать только (виртуальные)
> методы интерфейсов. Вот мои мучения вокруг этого:
> http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05


Delegates — типичное решение для этого ограничения generics. В C# они могут быть анонимными. Конечно, будет runtime cost и всё такое, но это уже другой вопрос.

А вообщем, имеет мало смысла пытаться перевести код с templates на generics по причине их фундаментальных различий. Нужно с нуля его разрабатывать, учитывая возможности и ограничения generics.
Posted via RSDN NNTP Server 1.9
Re[5]: А generic-и так могут?
От: alexeiz  
Дата: 02.06.05 08:45
Оценка:
"McSeem2" <12737@users.rsdn.ru> wrote in message
news:1201590@news.rsdn.ru
> Bottom line:
> Генерики, что в C#, что в Java — это чисто так, гламурненько. А
> шаблоны в C++ — это ГОТИЧНО!

leet speak?
Posted via RSDN NNTP Server 1.9
Re[5]: А generic-и так могут?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 02.06.05 09:43
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>"Павел Кузнецов" <5834@users.rsdn.ru> wrote in message

A>news:1201223@news.rsdn.ru
>> Так тоже не получится: generics умеют вызывать только (виртуальные)
>> методы интерфейсов. Вот мои мучения вокруг этого:
>> http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05


A>Delegates — типичное решение для этого ограничения generics. В C# они могут быть анонимными. Конечно, будет runtime cost и всё такое, но это уже другой вопрос.


A>А вообщем, имеет мало смысла пытаться перевести код с templates на generics по причине их фундаментальных различий. Нужно с нуля его разрабатывать, учитывая возможности и ограничения generics.


Ну это я уже начал понимать. А как нужное мне решение может выглядеть на generic-ах?
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: А generic-и так могут?
От: L.C.R. Россия lj://_lcr_
Дата: 20.06.05 21:37
Оценка:
McSeem2,

ПК>>Так тоже не получится: generics умеют вызывать только (виртуальные) методы интерфейсов. Вот мои мучения вокруг этого: http://rsdn.ru/Forum/Message.aspx?mid=979456
Автор: Павел Кузнецов
Дата: 10.01.05
Вот ссылка на мнение Брюса Эккеля по этому поводу: http://rsdn.ru/Forum/Message.aspx?mid=989922
Автор: Павел Кузнецов
Дата: 17.01.05


MS>Bottom line:

MS>Генерики, что в C#, что в Java — это чисто так, гламурненько. А шаблоны в C++ — это ГОТИЧНО!

Что же ты тогда скажешь про макросы в ЛИСПЕ!?
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re: А generic-и: попытка упростить описание
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 24.06.05 20:23
Оценка:
Еще раз здравствуйте.

Признаю, что в исходном посте я сделал слишком объемное и сложное описание. Приношу свои извинения.
Попробую сделать его попроще.

Итак, существует некий механизм доставки сообщений получателям. В этом механизме есть:
// Базовый класс для сообщений.
class msg_t { ... };

// Базовый класс для пунктов назначений (адресов получателей и отправителей сообщений).
class dest_t { ... };

// Метод для маршрутизации сообщения:
void
route(
    // Куда должно идти сообщение.
    const dest_t & to,
    // Само сообщение.
    const msg_t & msg,
    // От кого идет сообщение.
    const dest_t & reply_to,
    // Еще какие-то параметры, суть которых сейчас не важна
    ... );


Если кому-то нужно было отослать сообщение, то выполнялось это просто, например, так:
route( some_dest_t( "recipient" ), some_message_t( "hello!" ), some_dest_t( "sender" ) );


А вот с получением сообщения было сложнее. Каждый, кто хотел получать сообщения, должен был подписаться на него и зарегистрировать специальный объект-почтальон. Метод route пробегался по всем зарегистрированным получателям и, если находил нужного, то передавал сообщение почтальону.

Почтальоны были двух видов: синхронные, которые сразу инициировали обработку сообщения внутри route, и асинхронные, которые ставили сообщение в очередь объектам-агентам, а сообщение обрабатывалось тогда, когда агент разгребал свою очередь и извлекал оттуда сообщение. Далее речь пойдет именно об асинхронных почтальонах.

Задача асинхронного почтальона в том, чтобы преобразовать тройку значений <to, msg, reply_to> в один динамически созданный объект. Казалось бы, что здесь можно было бы обойтись готовой структурой:
struct    so_message_t
    {
        std::auto_ptr< dest_t >    m_to;
        std::auto_ptr< msg_t >    m_msg;
        std::auto_ptr< dest_t >    m_reply_to;
    };

и сделать одного почтальона, который бы генерировал объекты so_message_t. Но, проблема в том, что агенты хотят работать с конкретными типами пунктов назначений и сообщений. Т.е., чтобы so_message_t было шаблоном:
template< class Msg, class To, class Reply_to >
struct    so_msg_templ_t
    {
        std::auto_ptr< To >    m_to;
        std::auto_ptr< Msg >    m_msg;
        std::auto_ptr< Reply_to >    m_reply_to;
    };

А почтальон бы автоматически приводил бы указатели от базовых типов (dest_t, msg_t) к производным типам (To, Msg, Reply_to).

Собственно такой шаблон сообщения и такой шаблон почтальона был создан. Более того, шаблон почтальона был сделан так, чтобы он не был строго завязан на тип so_msg_templ_t -- реальный тип сообщения задавался параметром. Такая схема отлично работала несколько лет. Но в коде шаблона почтальона был явно зашит вызов конструктора сообщения:
so_postman_templ_t::deliver( /* параметры из route */ )
    {
        ... new Message_type( to.clone(), msg.clone(), reply_to.clone() ) ...
    }

Причем конструктора с тремя параметрами!
За время работы с so_postman_templ_t было сделано много кода и в качестве сообщений для агентов использовались не только инстанции шаблона so_msg_templ_t, но и не шаблонные типы сообщения. Последнее очень важно, т.к. у класса so_msg_templ_t можно изменить конструктор (что и было сделано), а вот у не шаблонных объектов-сообщений сделать это тяжело. И, что еще важно, где-то so_postman_templ_t использовался напрямую, а где-то применялись производные от него типы (так же шаблонные).

Итак, в один прекрасный день потребовалось поддержать сообщения, которые кроме трех основных параметров должны были получать еще один. И встала задача переделать класс so_postman_templ_t так, чтобы он мог либо вызывать конструктор с тремя аргументами, либо конструктор с четырьмя аргументами. Т.е. что-то вроде:
so_postman_templ_t::deliver( /* параметры из route */ )
    {
        if( Extended_info_supported )
            // Используем конструктор с четырьмя параметрами.
            ... new Message_type( to.clone(), msg.clone(), reply_to.clone(), extended_info.clone() ) ...
        else
            // Используем конструктор с тремя параметрами.
            ... new Message_type( to.clone(), msg.clone(), reply_to.clone() ) ...
    }

Где Extended_info_suppored -- это новый параметр шаблона, который по-умолчанию устанавливается в false.
Но именно так записать нельзя, т.к. тогда бы компилятор требовал бы у Message_type обоих конструкторов.
Поэтому пришлось искать решение через специализацию. Не нужна была бы поддержка VC++6.0, то можно было бы сделать частную специализацию so_postman_templ_t для случая, когда Extended_info_supported == true. Но поддерживать VC++6.0 потребовалось, поэтому пришлось использовать вспомогательные типы:
struct    no_extended_info_support_sender_t
    {
            // Используем конструктор с тремя параметрами.
            ... new Message_type( to.clone(), msg.clone(), reply_to.clone() ) ...
    };

struct    extended_info_support_sender_t
    {
            // Используем конструктор с четырьмя параметрами.
            ... new Message_type( to.clone(), msg.clone(), reply_to.clone(), extended_info.clone() ) ...
    };

template< bool Extended_info_supported >
struct    sender_selector_t
    {
        typedef no_extended_info_support_sender_t    sender_type_t;
    };

template<>
struct    sender_selector_t< true >
    {
        typedef extended_info_support_sender_t    sender_type_t;
    };

Вот как раз тип sender_selector_t и его полная специализация для Extended_info_supported==true и определяли, какой конструктор Message_type будет использоваться:
template< class    Mbapi_type, class    Sobj_type, class To_type = mbapi_3::dest_t, class    Reply_to_type = mbapi_3::dest_t,
    bool Extended_info_supported = false >
class    so_postman_templ_t : public postman_t {
    ...
    //! Объект, который реально будет осущетвлять доставку сообщения.
    const typename impl::sender_selector_t<
                    Extended_info_supported >::sender_type_t
            m_sender;
    ...
};

Если Extended_info_supported == false, то у объекта m_sender был тип no_extended_info_support_sender_t и у Message_type вызывался конструктор с тремя параметрами. В противном случае у m_sender был тип extended_info_support_sender_t и у Message_type вызывался конструктор с четырьмя параметрами.

Благодоря фокусу с параметром шаблона по-умолчанию Extended_info_supported весь старый код, в котором было написано что-то типа:
new so_postman_templ_t< some_message_t, some_async_message_t, some_dest_t >( ... );

остался полностью работоспособным.



Надеюсь, что это описание будет доступнее. Полный же код реализованного решения приведен в исходном сообшении.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: А generic-и: попытка упростить описание
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.06.05 21:50
Оценка: 46 (3)
Здравствуйте, eao197, Вы писали:
E>Признаю, что в исходном посте я сделал слишком объемное и сложное описание. Приношу свои извинения.
E>Попробую сделать его попроще.
Спасибо. Я правильно понял, что суть проблемы сводится к следующему:
1. У нас был универсальный класс нетипизированного сообщения
2. У нас был шаблонный класс типизированного сообщения, унаследованный от нетипизированного
3. У нас были нешаблонные классы-потомки нетипизированного сообшения
4. У всех классов были конструкторы с тремя параметрами, что использовалось внутри кода доставки для порождения новых сообщений.

Не вполне понятно, как выглядит теперь сигнатура метода Deliver и откуда брать четвертый параметр для сообщений, у которых его нет. Ну да ладно. Попробуем так угадать.

Итак, как бы это работало на C# 2.0?
Начнем с конца.
Поскольку дженерики не позволяют использовать никаких конструкторов вообще, кроме как конструктора без параметров, то нам пришлось бы придумывать какой-то другой метод создания объектов-сообщений.
Вариант 1 — использовать Reflection.
using System.Reflection;

public class Postman<MessageType> 
{
  public void Deliver(Destination to, Msg msd, Destination replyTo)
    {
        ConstructorInfo messageCtor = typeof(MessageType).GetConstructor(new Type[]{typeof(Destination),typeof(Msg), typeof(Destination)});
        if (messageCtor != null)
            MessageType msg = (MessageType)messageCtor.Invoke(new object[]{to, msg, replyTo};
    }
}

В таком случае все, что нам надо от жизни для реализации ExtendedDeliver — это добавить пару строк:
public class Postman<MessageType> 
{
  public void ExtendedDeliver(Destination to, Msg msd, Destination replyTo, Extended extended)
    {
        MessageType msg = null;
        ConstructorInfo messageCtor = typeof(MessageType).GetConstructor(new Type[]{typeof(Destination),typeof(Msg), typeof(Destination), typeof(Extended)});
        if (messageCtor != null)
            msg = (MessageType)messageCtor.Invoke(new object[]{to, msg, replyTo, extended};
        else // попробуем найти старый конструктор
        {
            messageCtor = typeof(MessageType).GetConstructor(new Type[]{typeof(Destination),typeof(Msg), typeof(Destination)});
            if (messageCtor != null)
                msg = (MessageType)messageCtor.Invoke(new object[]{to, msg, replyTo};
        }
    }
}

Как видим, все получилось и намного компактнее, чем на C++.
Конечно, в реальной жизни такой подход скорее всего будет быстро соптимизирован — уж очень плохо вставлять постоянный поиск конструктора.
Поэтому на практике, для сообщений скорее всего будет применяться фабрика. И приплясываний с бубном не потребуется вообще.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: А generic-и: попытка упростить описание
От: Павел Кузнецов  
Дата: 24.06.05 23:07
Оценка: 14 (1) +1 :)
Sinclair,

> Вариант 1 — использовать Reflection.

>
> public class Postman<MessageType>
> {
>   public void Deliver(Destination to, Msg msd, Destination replyTo)
>     {
>         ConstructorInfo messageCtor = typeof(MessageType).GetConstructor(new Type[]{typeof(Destination),typeof(Msg), typeof(Destination)});
>         if (messageCtor != null)
>             MessageType msg = (MessageType)messageCtor.Invoke(new object[]{to, msg, replyTo};
>     }
> }
>


Очень неплохо Есть, правда, кой-какие недостатки по сравнению с оригинальным решением (пережить, наверное, можно, но неприятно):
  • нет статической проверки типов, все смещается на время исполнения
  • насколько я понимаю, не будут работать конструкторы MessageType с неточным совпадением типов (например, принимающие ссылку на базовый класс)
  • если я не ошибаюсь, не будут работать шаблоны конструкторов MessageType

    >
    > public class Postman<MessageType>
    > {
    >   public void ExtendedDeliver(Destination to, Msg msd, Destination replyTo, Extended extended)
    >     {
    >         MessageType msg = null;
    >         ConstructorInfo messageCtor = typeof(MessageType).GetConstructor(new Type[]{typeof(Destination),typeof(Msg), typeof(Destination), typeof(Extended)});
    >         if (messageCtor != null)
    >             msg = (MessageType)messageCtor.Invoke(new object[]{to, msg, replyTo, extended};
    >         else // попробуем найти старый конструктор
    >         {
    >             messageCtor = typeof(MessageType).GetConstructor(new Type[]{typeof(Destination),typeof(Msg), typeof(Destination)});
    >             if (messageCtor != null)
    >                 msg = (MessageType)messageCtor.Invoke(new object[]{to, msg, replyTo};
    >         }
    >     }
    > }
    >


    Но, вообще

    > Как видим, все получилось и намного компактнее, чем на C++.


    В C++, если бы eao197 не пришлось мучиться с VC++ 6.0, было бы не длиннее.
    Posted via RSDN NNTP Server 2.0 beta
  • Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Re[4]: А generic-и: попытка упростить описание
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 25.06.05 00:10
    Оценка:
    Здравствуйте, Павел Кузнецов, Вы писали:

    ПК>Очень неплохо Есть, правда, кой-какие недостатки по сравнению с оригинальным решением (пережить, наверное, можно, но неприятно):

    ПК>
  • нет статической проверки типов, все смещается на время исполнения
    Тут ничего не поделаешь. Можно было бы обойти этот момент, если бы была возможность требовать не только пустой new.
    Максимум удобства, который можно получить — это выполнить поиск конструктора заранее, в статическом инициализаторе. И, соответственно, кинуть исключение. Тогда падение произойдет на очень раннем этапе (в случае удачи — прямо на старте приложения), и вся необходимая информация попадет именно к тому, кому нужно.

    ПК>
  • насколько я понимаю, не будут работать конструкторы MessageType с неточным совпадением типов (например, принимающие ссылку на базовый класс)
    Хороший вопрос... Нет. В доке сказано, что дефолтный биндер, применяемый при поиске мемберов, учитывает все стандартные приведения:

    The following table lists the conversions supported by the default binder.

    Source Type   | Target Type 
    ------------------------
    Any type      | Its base type. 
    Any type      | The interface it implements. 
    Char          | Unt16, UInt32, Int32, UInt64, Int64, Single, Double 
    Byte          | Char, Unt16, Int16, UInt32, Int32, UInt64, Int64, Single, Double 
    SByte         | Int16, Int32, Int64, Single, Double 
    UInt16        | UInt32, Int32, UInt64, Int64, Single, Double 
    Int16         | Int32, Int64, Single, Double 
    UInt32        | UInt64, Int64, Single, Double 
    Int32         | Int64, Single, Double 
    UInt64        | Single, Double 
    Int64         | Single, Double 
    Single        | Double 
    Non-reference | By-reference.


    Кстати, похоже я прогнал. В примечаниях MSDN к Type.GetConstructor приведена такая фраза:

    If the current Type represents a type parameter of a generic type or method, this method always returns null.

    Что, вообще-то, очень странно. Впрочем, существует набор способов это обойти.
    ПК>
  • если я не ошибаюсь, не будут работать шаблоны конструкторов MessageType
    Это я не понял. Ты что имеешь в виду?
    Я-то имел в виду вот что:
    public class MessageType<To, Msg, ReplyTo>
    where 
        To: Destination;
        Msg: Messsage;
        ReplyTo: Destination
    {
        public MessageType(To to, Msg msg, ReplyTo r) // типизированный конструктор 
        {
        }
    }

    Именно этот конструктор мы и ищем.
    ПК>В C++, если бы eao197 не пришлось мучиться с VC++ 6.0, было бы не длиннее.
    Может быть.
    ... << RSDN@Home 1.1.4 beta 5 rev. 395>>
  • Уйдемте отсюда, Румата! У вас слишком богатые погреба.
    Re[5]: А generic-и: попытка упростить описание
    От: Павел Кузнецов  
    Дата: 25.06.05 03:11
    Оценка:
    Здравствуйте, Sinclair, Вы писали:

    ПК>>
  • нет статической проверки типов, все смещается на время исполнения

    S>Тут ничего не поделаешь. Можно было бы обойти этот момент, если бы была возможность требовать не только пустой new.


    Не очень понял, а как бы ты написал требования, если нужно выбрать один из двух конструкторов, а не требовать какой-либо из них?..

    ПК>>
  • если я не ошибаюсь, не будут работать шаблоны конструкторов MessageType

    S>Это я не понял. Ты что имеешь в виду?

    class MyMessageType
    {
    public:
      template<class To, class Msg, class ReplyTo>
      MyMessageType(To const&, Msg const&, ReplyTo const&);
    };

    Такое может быть нужно, чтоб "сфотографировать" полный тип аргументов при инициализации, как, например, это делает boost::shared_ptr.
  • Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.