Re[6]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 11:47
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>On 09/18/2011 05:18 PM, Galiulin Rishat Faimovich wrote:


>>> > Спасибо за ваше мнение. Я действительно пишу на С++ довольно короткое время —

>>> > всего 1 год, до этого я писал на Java.
>>
>> MZ>Интересно, как же ты эту проблему на Java-то решал.
>>
>> Никогда не решал такую проблему на Java.

MZ>А что ж на плюсах-то припёрло ?

MZ>Одинаковые же проблемы.

Для меня это не явлется проблемой, но большенсво коллег проголосовало за ввод IN, IN_OUT и OUT define-овю.
Как я уже ответил одному из участников, я просто заменил неконтролируемые компилятором define-ы на шаблоны.
Re[9]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 19.09.11 11:55
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Здравствуйте, k.o., Вы писали:


KO>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>>Вроде написал более рабочий вариант specification.hpp:


KO>>Да, уже лучше, только у нас, по прежнему, не поддерживается преобразование unique_ptr<A> -> unique_ptr<const A>, можно, конечно, сделать его явно:


GRF>Да, действительно выглядит плохо . Но можно немного короче


Так ведь можно и ещё короче, если не использовать эти обёртки для параметров.

KO>>Кроме того, у этого подхода есть ещё, скажем так, концептуальная проблема, из-за того что некоторые способы передачи параметров не укладываются в in, in_out и out. Например, мы хотим передавать владение unique_ptr дальше по цепочке вызовов:


KO>>
KO>>void sink( std::unique_ptr< const A > arg)
KO>>{
KO>>}
 
KO>>void sink1( std::unique_ptr< const A > arg)
KO>>{
KO>>  sink(std::move(arg));
KO>>}
KO>>


GRF>А где здесь проблема? Можете подробнее? У меня вроде вот этот код работает

GRF>
GRF>void sink( in< std::unique_ptr< const A > > arg)
GRF>{
GRF>}

GRF>void sink1( in< std::unique_ptr< const A > > arg)
GRF>{
GRF>  sink( std::move( arg ) );
GRF>}
GRF>


Нужно чтобы работал вот такой код:

void sink1( in< std::unique_ptr< const A > > arg)
{
  sink( in_( std::move( arg() ) ) );
}


Понятно, что саму обёртку можно, без проблем, передать дальше.

KO>>После этого можно будет вспомнить о существовании rvalue-references и необходимости поддерживать perfect forwarding.


GRF>При реализации мы к сожалению не ориетировались на новый стандарт С++


Ну это, как бы, заметно, хотя и странно для, подобного рода, инфраструктурного кода.
Re[9]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 19.09.11 12:03
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Если нет ни

GRF>
GRF>MyType ::operator+( const MyType& lhs, const MyType& rhs );
GRF>

GRF>ни
GRF>
GRF>MyType MyType::operator+( const MyType& rhs);
GRF>

GRF>зачем нужен
GRF>
GRF>MyType operator+( in< MyType& > lhs, in< MyType& > rhs );
GRF>

GRF>?

Так это же вы предлагали вместо

void function_0( const Base& paramIn )


писать

void function_0( in< Base& > paramIn )


Соответственно, вместо 'operator+(const MyType& lhs, const MyType& rhs)' у нас должен быть 'operator+(in<MyType&> lhs, in<MyType&> rhs)'. Если это не так, возникает вопрос, в чём разница?

KO>>Или, может, предлагается использовать такой подход не для всех функций? Тогда, пожалуй, стоит перечислить сценарии, в которых предполагается это использовать, в исходном сообщении об этом ничего не было сказано.


GRF>in, in_out и out должны использваться в теле функций или в вызовах функций


Вопрос в том, для каких функций параметры должны объявляться с использованием in, in_out и out?
Re[10]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 12:29
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Здравствуйте, k.o., Вы писали:


KO>>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>>>Вроде написал более рабочий вариант specification.hpp:


KO>>>Да, уже лучше, только у нас, по прежнему, не поддерживается преобразование unique_ptr<A> -> unique_ptr<const A>, можно, конечно, сделать его явно:


GRF>>Да, действительно выглядит плохо . Но можно немного короче


KO>Так ведь можно и ещё короче, если не использовать эти обёртки для параметров.


KO>>>Кроме того, у этого подхода есть ещё, скажем так, концептуальная проблема, из-за того что некоторые способы передачи параметров не укладываются в in, in_out и out. Например, мы хотим передавать владение unique_ptr дальше по цепочке вызовов:


KO>>>
KO>>>void sink( std::unique_ptr< const A > arg)
KO>>>{
KO>>>}
 
KO>>>void sink1( std::unique_ptr< const A > arg)
KO>>>{
KO>>>  sink(std::move(arg));
KO>>>}
KO>>>


GRF>>А где здесь проблема? Можете подробнее? У меня вроде вот этот код работает

GRF>>
GRF>>void sink( in< std::unique_ptr< const A > > arg)
GRF>>{
GRF>>}

GRF>>void sink1( in< std::unique_ptr< const A > > arg)
GRF>>{
GRF>>  sink( std::move( arg ) );
GRF>>}
GRF>>


KO>Нужно чтобы работал вот такой код:


KO>
KO>void sink1( in< std::unique_ptr< const A > > arg)
KO>{
KO>  sink( in_( std::move( arg() ) ) );
KO>}
KO>


Попробуйте, пожалуйста, это:
void sink1( in< std::unique_ptr< const A > > arg)
{
  sink( in_( std::move( arg()() ) ) );
}



KO>Понятно, что саму обёртку можно, без проблем, передать дальше.


KO>>>После этого можно будет вспомнить о существовании rvalue-references и необходимости поддерживать perfect forwarding.


GRF>>При реализации мы к сожалению не ориетировались на новый стандарт С++


KO>Ну это, как бы, заметно, хотя и странно для, подобного рода, инфраструктурного кода.


Для нас сейчас самое важное надежность и переносимость.
Re[11]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 19.09.11 13:03
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Попробуйте, пожалуйста, это:

GRF>
GRF>void sink1( in< std::unique_ptr< const A > > arg)
GRF>{
GRF>  sink( in_( std::move( arg()() ) ) );
GRF>}
GRF>


А самому? Вас же на ideone.com не забанили, надеюсь? В любом случае, результатом arg() будет константная ссылка на unique_ptr<const A>, у которого, разумеется, нет оператора ().

Попробуйте повторить этот пример используя ваш specification.hpp.
Re[12]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 13:10
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Попробуйте, пожалуйста, это:

GRF>>
GRF>>void sink1( in< std::unique_ptr< const A > > arg)
GRF>>{
GRF>>  sink( in_( std::move( arg()() ) ) );
GRF>>}
GRF>>


KO>А самому? Вас же на ideone.com не забанили, надеюсь? В любом случае, результатом arg() будет константная ссылка на unique_ptr<const A>, у которого, разумеется, нет оператора ().


KO>Попробуйте повторить этот пример используя ваш specification.hpp.


Тогда я не понял ваш переидущий ответ
KO>>>Кроме того, у этого подхода есть ещё, скажем так, концептуальная проблема, из-за того что некоторые способы передачи параметров не укладываются в in, in_out и out. Например, мы хотим передавать владение unique_ptr дальше по цепочке вызовов:

KO>>>
KO>>>void sink( std::unique_ptr< const A > arg)
KO>>>{
KO>>>}
 
KO>>>void sink1( std::unique_ptr< const A > arg)
KO>>>{
KO>>>  sink(std::move(arg));
KO>>>}
KO>>>


GRF>>А где здесь проблема? Можете подробнее? У меня вроде вот этот код работает

GRF>>
GRF>>void sink( in< std::unique_ptr< const A > > arg)
GRF>>{
GRF>>}

GRF>>void sink1( in< std::unique_ptr< const A > > arg)
GRF>>{
GRF>>  sink( std::move( arg ) );
GRF>>}
GRF>>


KO>Нужно чтобы работал вот такой код:


KO>
KO>void sink1( in< std::unique_ptr< const A > > arg)
KO>{
KO>  sink( in_( std::move( arg() ) ) );
KO>}
KO>


KO>Понятно, что саму обёртку можно, без проблем, передать дальше.


Зачем тогда здесь скобки у arg ?
Re[13]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 19.09.11 13:20
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Здравствуйте, k.o., Вы писали:


KO>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>Тогда я не понял ваш переидущий ответ


GRF>Зачем тогда здесь скобки у arg ?


Вы меня спрашиваете для чего предназначен 'operator()' у вашего класаа in?

KO>>Попробуйте повторить этот пример используя ваш specification.hpp.
Re[14]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 14:03
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Здравствуйте, k.o., Вы писали:


KO>>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Тогда я не понял ваш переидущий ответ


GRF>>Зачем тогда здесь скобки у arg ?


KO>Вы меня спрашиваете для чего предназначен 'operator()' у вашего класаа in?


KO>>>Попробуйте повторить этот пример используя ваш specification.hpp.


Спасибо, понял проблему. Надо об этом подумать.
Re[7]: Реализация IN, IN-OUT и OUT параметров функций
От: Аноним  
Дата: 19.09.11 17:59
Оценка:
Здравствуйте, alexeiz, Вы писали:

А>> Я в первые один-два года на C++ тоже ваял шаблонные кошмары а ля Александреску (я тогда и не знал, кто это такой), потому что прикольно это было. Половину буста переизобрел, не догадываясь о его существовании.


A>Самому себе польстить — святое дело!


Ну если хочешь, могу еще тебе посочувствовать.
Re[8]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 18:36
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>>> Я в первые один-два года на C++ тоже ваял шаблонные кошмары а ля Александреску (я тогда и не знал, кто это такой), потому что прикольно это было. Половину буста переизобрел, не догадываясь о его существовании.


A>>Самому себе польстить — святое дело!


А>Ну если хочешь, могу еще тебе посочувствовать.


Пожалуйста, не превращайте данный топик в "междоусобчик". Нам очень нужны Ваши советы
Re[14]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 20:53
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Здравствуйте, k.o., Вы писали:


KO>>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Тогда я не понял ваш переидущий ответ


GRF>>Зачем тогда здесь скобки у arg ?


KO>Вы меня спрашиваете для чего предназначен 'operator()' у вашего класаа in?


KO>>>Попробуйте повторить этот пример используя ваш specification.hpp.


Вот измененный вариант specification.hpp
#ifndef SPECIFICATION_HPP
#    define SPECIFICATION_HPP

#    include <ostream>

#    if 1 // in< class Type > - Functions input parameter

/**
 * @brief Functions input parameter
 * @tparam Type none reference input parameter type
 */
template< class Type >
class in
{
    template< class InType >
    friend in< InType > in_( const InType value );

public:

    /**
     * Cast operator
     * @return input parameter value
     */
    operator Type&( ) const
    {
        return value_;
    }

    /**
     * Gets parameter value
     * @return input parameter value
     */
    Type& operator ( )( ) const
    {
        return value_;
    }

private:

    /**
     * Initialization constructor
     * @param value input parameter value
     */
    explicit in( Type& value ): value_( value ) { }

    template< class OtherType >
    in( const OtherType& value ); // disable implicit conversion for none reference objects

    /**
     * input parameter value
     */
    Type& value_;
};

template< class Type >
in< Type& > in_ref_( const Type& value );

/**
 * @brief Functions input parameter
 * @tparam Type reference input parameter type
 */
template< class Type >
class in< Type& >
{
    template< class InType >
    friend in< InType& > in_ref_( const InType& value );

public:

    /**
     * Cast operator
     * @return input parameter value
     */
    operator const Type&( ) const
    {
        return value_;
    }

    /**
     * Cast operator
     * @return input parameter value
     */
    template< class BaseType >
    operator in< BaseType& >( ) const
    {
        return in_ref_< BaseType > ( value_ );
    }

    /**
     * Gets parameter value
     * @return input parameter value
     */
    const Type& operator ( )( ) const
    {
        return value_;
    }

private:

    /**
     * Initialization constructor
     * @param value input parameter value
     */
    explicit in( const Type& value ): value_( value ) { }

    /**
     * input parameter value
     */
    const Type& value_;
};

/**
 * @brief Functions input parameter
 * @tparam Type pointer input parameter type
 */
template< class Type >
class in< Type* >
{
    template< class InType > friend in< InType >
    in_( const InType value );

public:

    /**
     * Cast operator
     * @return input parameter value
     */
    operator const Type*( ) const
    {
        return value_;
    }

    /**
     * Gets parameter value
     * @return input parameter value
     */
    const Type* operator ( )( ) const
    {
        return value_;
    }

    /**
     * Member selection by pointer operator
     * @return input parameter value
     */
    const Type* operator ->( ) const
    {
        return value_;
    }

private:

    /**
     * Initialization constructor
     * @param value input parameter value
     */
    explicit in( const Type * const value ): value_( value ) { }

    /**
     * input parameter value
     */
    const Type * const value_;
};

/**
 * Function call input parameter specifier
 * @param value input parameter value
 * @return  input parameter
 */
template< class Type >
in< Type > in_( Type value )
{
    return in< Type > ( value );
}

/**
 * Function call input parameter by reference specifier
 * @param value input parameter value
 * @return  input parameter
 */
template< class Type >
in< Type& > in_ref_( const Type& value )
{
    return in< Type& >( value );
}
#    endif

#    if 1 // in_out< class Type& > - Functions input-output parameter

/**
 * @brief Functions input-output parameter
 * @tparam Type none pointer input-output parameter type
 */
template< class Type >
class in_out
{
    template< class InOutType >
    friend in_out< InOutType > in_out_( InOutType& value );

public:

    /**
     * Cast operator
     * @return input-output parameter value
     */
    operator Type&( ) const
    {
        return value_;
    }

    /**
     * Gets parameter value
     * @return input-output parameter value
     */
    Type& operator ( )( ) const
    {
        return value_;
    }

    /**
     * Assignment operator
     * @param value         assignment value
     * @tparam ValueType    assignment value type
     * @return input-output parameter value
     */
    template< class ValueType >
    Type& operator =(const ValueType& value )
    {
        return value_ = value;
    }

private:

    /**
     * Initialization constructor
     * @param value input-output parameter value
     */
    explicit in_out( Type& value ): value_( value ) { }

    /**
     * input-output parameter value
     */
    Type& value_;
};

/**
 * @brief Functions input-output parameter
 * @tparam Type pointer input-output parameter type
 */
template< class Type >
class in_out< Type* >
{
    template< class InOutType >
    friend in_out< InOutType > in_out_( InOutType& value );

public:

    /**
     * Cast operator
     * @return input-output parameter value
     */
    operator Type* &( ) const
    {
        return value_;
    }

    /**
     * Gets parameter value
     * @return input-output parameter value
     */
    Type* & operator ( )( ) const
    {
        return value_;
    }

    /**
     * Assignment operator
     * @param value         assignment value
     * @tparam ValueType    assignment value type
     * @return input-output parameter value
     */
    Type* & operator =( Type* value )
    {
        return value_ = value;
    }

    /**
     * Member selection by pointer operator
     * @return input-output parameter value
     */
    Type* operator ->( ) const
    {
        return value_;
    }

private:

    /**
     * Initialization constructor
     * @param value input-output parameter value
     */
    explicit in_out( Type* & value ): value_( value ) { }

    /**
     * input-output parameter value
     */
    Type* & value_;
};

/**
 * Function call input-output parameter specifier
 * @param value input-output parameter value
 * @return  input-output parameter
 */
template< class Type >
in_out< Type >
in_out_( Type& value )
{
    return in_out< Type > ( value );
}
#    endif

#    if 1 // out< class Type* > - Functions output parameter

/**
 * @brief Functions output parameter
 * @tparam Type none pointer output parameter type
 */
template< class Type >
class out
{
    template< class OutType >
    friend out< OutType > out_( OutType& value );

public:

    /**
     * Cast operator
     * @return output parameter value
     */
    operator Type&( ) const
    {
        return value_;
    }

    /**
     * Gets parameter value
     * @return output parameter value
     */
    Type& operator ( )( ) const
    {
        return value_;
    }

    /**
     * Assignment operator
     * @param value         assignment value
     * @tparam ValueType    assignment value type
     * @return output parameter value
     */
    template< class ValueType >
    Type& operator =(const ValueType& value )
    {
        return value_ = value;
    }

    /**
     * Checks if parameter is used
     * @return <code>true</code> if parameter has been set and <code>false</code> otherwise
     */
    bool
    used( )
    {
        return ( &value_ ) != NULL;
    }

    /**
     * Checks if parameter is not used
     * @return <code>true</code> if parameter has not been set and <code>false</code> otherwise
     */
    bool
    not_used( )
    {
        return !used( );
    }

    /**
     * Creates unused parameter indicator
     * @return unused parameter indicator
     */
    static out
    unused( )
    {
        return out( *reinterpret_cast<Type*> ( NULL ) );
    }

private:

    /**
     * Initialization constructor
     * @param value output parameter value
     */
    explicit out( Type& value ): value_( value ) { }

    /**
     * output parameter value
     */
    Type& value_;
};

/**
 * @brief Functions output parameter
 * @tparam Type pointer output parameter type
 */
template< class Type >
class out< Type* >
{
    template< class OutType >
    friend out< OutType > out_( OutType& value );

public:

    /**
     * Cast operator
     * @return output parameter value
     */
    operator Type* &( ) const
    {
        return value_;
    }

    /**
     * Gets parameter value
     * @return output parameter value
     */
    Type* & operator ( )( ) const
    {
        return value_;
    }

    /**
     * Assignment operator
     * @param value         assignment value
     * @tparam ValueType    assignment value type
     * @return output parameter value
     */
    Type* & operator =( Type* value )
    {
        return value_ = value;
    }

    /**
     * Member selection by pointer operator
     * @return output parameter value
     */
    Type* operator ->( ) const
    {
        return value_;
    }

    /**
     * Checks if parameter is used
     * @return <code>true</code> if parameter has been set and <code>false</code> otherwise
     */
    bool
    used( )
    {
        return ( &value_ ) != NULL;
    }

    /**
     * Checks if parameter is not used
     * @return <code>true</code> if parameter has not been set and <code>false</code> otherwise
     */
    bool
    not_used( )
    {
        return !used( );
    }

    /**
     * Creates unused parameter indicator
     * @return unused parameter indicator
     */
    static out
    unused( )
    {
        return out( *reinterpret_cast<Type**> ( NULL ) );
    }

private:

    /**
     * Initialization constructor
     * @param value output parameter value
     */
    explicit out( Type* & value ): value_( value ) { }

    /**
     * output parameter value
     */
    Type* & value_;
};

/**
 * Function call output parameter specifier
 * @param value output parameter value
 * @return  output parameter
 */
template< class Type >
out< Type >
out_( Type& value )
{
    return out< Type > ( value );
}
#    endif

/**
 * Ostream output operator
 * @param os            output stream
 * @param output        output value
 * @return output stream
 * @tparam CharType     @a os character type
 * @tparam OutputType   @a output type
 */
template< class CharType, class OutputType >
std::basic_ostream< CharType >& operator <<( in_out< std::basic_ostream< CharType > > os, const OutputType& output )
{
    return os( ) << output;
}

#endif /* SPECIFICATION_HPP */


Вроде теперь ваш пример работает
Re[15]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 20.09.11 05:58
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

KO>>>>Попробуйте повторить этот пример используя ваш specification.hpp.


GRF>Вроде теперь ваш пример работает


Зато, теперь не работает добавление константности:
void
sink2( in< const std::unique_ptr< const A > > arg )
{
  // would like to get compile error for attempts to modify arg, e.g.:
  // arg().release();
}

void
sink1( in< std::unique_ptr< const A > > arg )
{
    std::cout << "sink1 owns pointer to A: " << arg( ).get( ) << std::endl;
    sink2( in_( std::move( arg() ) ) );
    std::cout << "sink1 passed ownership to sink2: " << arg( ).get( ) << std::endl;
}


И, хотя, реализовать это нетрудно:

#include <type_traits>
...
template< class Type >
class in
{
public:

    in( const in<typename std::remove_const<Type>::type>& other)
    : value_(other())
    {
    }

...
};


Возникает закономерный вопрос: нафига козе баян зачем нам вся эта шаблонная магия с классом in, если мы теперь всё-равно можем менять передаваемые аргументы, а константность нужно добавлять самому, точно также, как и с обычными параметрами? Собственно, в этом и заключается "концептуальная проблема" вашего подхода: он либо слишком ограничивающий, либо, мало чем отличается (кроме лишней писанины) от обычной передачи параметров.
Re[16]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 20.09.11 06:56
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


KO>>>>>Попробуйте повторить этот пример используя ваш specification.hpp.


GRF>>Вроде теперь ваш пример работает


KO>Зато, теперь не работает добавление константности:

KO>
KO>void
KO>sink2( in< const std::unique_ptr< const A > > arg )
KO>{
KO>  // would like to get compile error for attempts to modify arg, e.g.:
KO>  // arg().release();
KO>}

KO>void
KO>sink1( in< std::unique_ptr< const A > > arg )
KO>{
KO>    std::cout << "sink1 owns pointer to A: " << arg( ).get( ) << std::endl;
KO>    sink2( in_( std::move( arg() ) ) );
KO>    std::cout << "sink1 passed ownership to sink2: " << arg( ).get( ) << std::endl;
KO>}
KO>


А для каких целей нужно будет добавление константности если полностью перейти на in, in_out, out нотацию?
Как я понимаю in параметр должен гарантировать толко неизменность передаваемого внешнего для функции параметра.
Re[17]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 20.09.11 12:01
Оценка: 2 (1)
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Здравствуйте, k.o., Вы писали:


KO>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


KO>>>>>>Попробуйте повторить этот пример используя ваш specification.hpp.


GRF>>>Вроде теперь ваш пример работает


KO>>Зато, теперь не работает добавление константности:


GRF>А для каких целей нужно будет добавление константности если полностью перейти на in, in_out, out нотацию?

GRF>Как я понимаю in параметр должен гарантировать толко неизменность передаваемого внешнего для функции параметра.

Многие (я в том числе) предпочитают обеспечивать, также, неизменяемость входных параметров внутри самой функции (см., например, "Совершенный Код" 2-е издание, изд. Питер, с. 173). Вы сами-то здесь
Автор: Galiulin Rishat Faimovich
Дата: 14.09.11
зачем заменили 'int* bar_in' на 'const int* const bar_in'? То, что в некоторых случаях их всё-таки имеет смысл делать изменяемыми, всего лишь, показывает ограниченность модели in/in_out/out (или, если хотите, системы типов C++). В принципе, всё это прекрасно решается введением соглашений об именовании параметров (например, добавлением префиксов in, inOut, out к именам параметров) и code review, но, в этом случае нет никакого смысла и в дополнительных обёртках, таких как ваши.
Re[18]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 20.09.11 13:12
Оценка: 1 (1)
Здравствуйте, k.o., Вы писали:

KO>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


GRF>>Здравствуйте, k.o., Вы писали:


KO>>>Здравствуйте, Galiulin Rishat Faimovich, Вы писали:


KO>>>>>>>Попробуйте повторить этот пример используя ваш specification.hpp.


GRF>>>>Вроде теперь ваш пример работает


KO>>>Зато, теперь не работает добавление константности:


GRF>>А для каких целей нужно будет добавление константности если полностью перейти на in, in_out, out нотацию?

GRF>>Как я понимаю in параметр должен гарантировать толко неизменность передаваемого внешнего для функции параметра.

KO>Многие (я в том числе) предпочитают обеспечивать, также, неизменяемость входных параметров внутри самой функции (см., например, "Совершенный Код" 2-е издание, изд. Питер, с. 173). Вы сами-то здесь
Автор: Galiulin Rishat Faimovich
Дата: 14.09.11
зачем заменили 'int* bar_in' на 'const int* const bar_in'? То, что в некоторых случаях их всё-таки имеет смысл делать изменяемыми, всего лишь, показывает ограниченность модели in/in_out/out (или, если хотите, системы типов C++). В принципе, всё это прекрасно решается введением соглашений об именовании параметров (например, добавлением префиксов in, inOut, out к именам параметров) и code review, но, в этом случае нет никакого смысла и в дополнительных обёртках, таких как ваши.


Ваши доводы, а также доводы MasterZiv: здесь
Автор: MasterZiv
Дата: 15.09.11
и здесь
Автор: MasterZiv
Дата: 18.09.11
, убедили и меня и коллег полностью отказаться от введения как IN, IN-OUT и OUT define-ов (они не контролируются компилятором и следовательно могут ввести в заблуждение), так и in, in_out и out шаблонов (они вводят сильные ограничения) и перейти на стандартную модель.
Re[19]: Реализация IN, IN-OUT и OUT параметров функций
От: Alca Украина  
Дата: 20.09.11 13:49
Оценка:
Я делаю так:
— IN параметры передаю по ссылке или по значению
— OUT параметры передаю по указателю
Re[20]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 20.09.11 14:48
Оценка:
Здравствуйте, Alca, Вы писали:

A>Я делаю так:

A> — IN параметры передаю по ссылке или по значению
A> — OUT параметры передаю по указателю

void print(const char *text);

Это передача входного параметра по значению или по указателю?
А если свой умный указатель захотите сделать, тоже по ссылке будете параметр передавать?
class my_smart_ptr_t
{
...
public:
  my_smart_ptr_t(T *p);
...
};


Ну и для OUT, тоже, какое-то странное ограничение.

Re[19]: Реализация IN, IN-OUT и OUT параметров функций
От: Аноним  
Дата: 21.09.11 20:26
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Ваши доводы, а также доводы MasterZiv: здесь
Автор: MasterZiv
Дата: 15.09.11
и здесь
Автор: MasterZiv
Дата: 18.09.11
, убедили и меня и коллег полностью отказаться от введения как IN, IN-OUT и OUT define-ов (они не контролируются компилятором и следовательно могут ввести в заблуждение), так и in, in_out и out шаблонов (они вводят сильные ограничения) и перейти на стандартную модель.


"Стандартную" это какую? Все-таки, в C++ не решены две проблемы:

1) отличения параметров "in-out" от "out" (разница в том, что в первом случае параметр перед вызовом функции должен быть установлен в определенное значение, от которого зависит выполнение функции, а во втором случае значение параметра до вызова функции неважно);

2) запись аргументов "in-out" и "in" при вызове функции при использовании ссылок (C++ way) ничем не отличается от передачи по значению:

void DoSomething(int inParam1, int inParam2, int& inoutParam, int& outParam)
{
}

int main()
{
    int a = 0, b = 0, c = 0, d = 0;

    DoSomething(a, b, c, d);

    return 0;
}


Я считаю, что пустые дефайны типа INOUT и OUT — все-таки более-менее нормальное решение, исключительно для аннотации.

#define INOUT
#define OUT

void DoSomething(int inParam1, int inParam2, INOUT int& inoutParam, OUT int& outParam)
{
}

int main()
{
    int a = 0, b = 0, c = 0, d = 0;

    DoSomething(a, b, INOUT c, OUT d);

    return 0;
}


Или можно ставить какие-нибудь комментарии.

void DoSomething(int inParam1, int inParam2, /*INOUT*/ int& inoutParam, /*OUT*/ int& outParam)
{
}

int main()
{
    int a = 0, b = 0, c = 0, d = 0;

    DoSomething(a, b, /*INOUT*/ c, /*OUT*/ d);

    return 0;
}


Честно говоря, мне самому оба решения не нравятся. Для меня это вопрос открытый.
Re[20]: Реализация IN, IN-OUT и OUT параметров функций
От: MasterZiv СССР  
Дата: 22.09.11 06:17
Оценка:
On 22.09.2011 0:26, Аноним 492 wrote:

> 1) отличения параметров "in-out" от "out" (разница в том, что в первом случае

> параметр перед вызовом функции должен быть установлен в определенное значение,
> от которого зависит выполнение функции, а во втором случае значение параметра до
> вызова функции неважно);

В отсутствии чистого OUT нет ничего страшного. Этого нет в очень многих
системах программирования.
Если IN в IN_OUT игнорируется телом функции, что ОЧЕНЬ легко и всегда
можно сделать, то проблемы вообще нет.

Во-вторых, можно просто сделать два параметра из одного IN_OUT, один
чисто IN, по значению, другой IN_OUT c семантикой только OUT.

В третьих, можно возвращать значения вообще с помощью того, что возвращает
функция. Не всегда это можно сделать, но можно.

> Я считаю, что пустые дефайны типа INOUT и OUT — все-таки более-менее нормальное

> решение, исключительно для аннотации.

Они ни от чего не спасают. Если бы это поддерживал язык, -- да, было бы хорошо.
А так -- всё равно всегда надо смотреть на сигнатуру вызываемой функции и проверять.
Posted via RSDN NNTP Server 2.1 beta
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.