Re[6]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 16.09.11 21:44
Оценка:
Вроде написал более рабочий вариант specification.hpp:
#ifndef SPECIFICATION_HPP
#   define SPECIFICATION_HPP

#   include <ostream>

/**
 * @brief Functions input parameter
 */
#   define IN
/**
 * @brief Functions input/output parameter
 */
#   define IN_OUT
/**
 * @brief Functions output parameter
 */
#   define OUT

#   if 1 // in< class Type > - Functions input parameter
/**
 * @brief Functions input parameter
 * @tparam Type none reference input parameter type
 */
template< class Type >
class in
{
public:
    /**
     * Initialization constructor
     * @param value input parameter value
     */
    explicit in( const Type value ): value_( value ) {}

    /**
     * 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_;
    }

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

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

/**
 * @brief Functions input parameter
 * @tparam Type reference input parameter type
 */
template< class Type >
class in< Type& >
{
public:
    /**
     * Initialization constructor
     * @param value input parameter value
     */
    explicit in( const Type& value ): value_( value ) {}

    /**
     * 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_;
    }

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

/**
 * @brief Functions input parameter
 * @tparam Type pointer input parameter type
 */
template< class Type >
class in< Type* >
{
public:
    /**
     * Initialization constructor
     * @param value input parameter value
     */
    explicit in( const Type* const value ): value_( value ) {}

    /**
     * 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:
    /**
     * input parameter value
     */
    const Type* const 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
{
public:
    /**
     * Initialization constructor
     * @param value input-output parameter value
     */
    explicit in_out( Type& value ): value_( value ) {}

    /**
     * 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:
    /**
     * 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* >
{
public:
    /**
     * Initialization constructor
     * @param value input-output parameter value
     */
    explicit in_out( Type* & value ): value_( value ) {}

    /**
     * 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:
    /**
     * input-output parameter value
     */
    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
{
public:
    /**
     * Initialization constructor
     * @param value output parameter value
     */
    explicit out( Type& value ): value_( value ) {}

    /**
     * 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:
    /**
     * output parameter value
     */
    Type& value_;
};

/**
 * @brief Functions output parameter
 * @tparam Type pointer output parameter type
 */
template< class Type >
class out< Type* >
{
public:
    /**
     * Initialization constructor
     * @param value output parameter value
     */
    explicit out( Type* & value ): value_( value ) {}

    /**
     * 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:
    /**
     * output parameter value
     */
    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[3]: Реализация IN, IN-OUT и OUT параметров функций
От: alexeiz  
Дата: 17.09.11 21:18
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Да согласен что писать надо больше и что выглядит не совсем так хотелось бы. Но есть и плюсы — код читабельнее.


Обоснуй свою точку зрения. Каким образом указывание типов параметров при вызове функции делает код читабельнее? Загромождаете код лишней информацией. Посмотри на свои вызовы функций. Через них же невозможно продраться.

GRF>А это в свою очередь как я с коллегами ожидаем уменьшит количество ошибок и облегчит дальнейшую поддержку.


Ты просто хочешь выдать желаемое за действительное.

GRF>Второй плюс — это то улучшает оптимизацию кода на icc и на gcc, к сожалению есть небольшой overhead на cl


Необоснованное заявление. С какой стати это может привести к более оптимизированному коду?
Re[4]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 18.09.11 06:43
Оценка:
Здравствуйте, alexeiz, Вы писали:

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


GRF>>Да согласен что писать надо больше и что выглядит не совсем так хотелось бы. Но есть и плюсы — код читабельнее.


A>Обоснуй свою точку зрения. Каким образом указывание типов параметров при вызове функции делает код читабельнее? Загромождаете код лишней информацией. Посмотри на свои вызовы функций. Через них же невозможно продраться.


Вы считаете что на момент вызова типы параметров лучше опустить? Мне с коллегами надо об этом подумать еще раз. Пока мы пришли к тому что типы парамтров покажут места приведения типов.

GRF>>А это в свою очередь как я с коллегами ожидаем уменьшит количество ошибок и облегчит дальнейшую поддержку.


A>Ты просто хочешь выдать желаемое за действительное.


Почему же? Ведь многие вводят IN, IN-OUT и OUT define-ы мы просто хотели избавиться от недостатков такого метода. Можете подробнее объяснить, почему вы с этим не согласны? Нам очень нужно ваше мнение.

GRF>>Второй плюс — это то улучшает оптимизацию кода на icc и на gcc, к сожалению есть небольшой overhead на cl


A>Необоснованное заявление. С какой стати это может привести к более оптимизированному коду?


Факт оптимизации мы увидели просматривая ассемблерные листинги как самих функций так и мест их вызова (компилиловать надо с опцией оптимизации иначе как минимум будут вставлены вызовы конструкторов и деструкторов).
Re[4]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 18.09.11 07:12
Оценка:
Здравствуйте, alexeiz, Вы писали:

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


GRF>>Да согласен что писать надо больше и что выглядит не совсем так хотелось бы. Но есть и плюсы — код читабельнее.


A>Обоснуй свою точку зрения. Каким образом указывание типов параметров при вызове функции делает код читабельнее? Загромождаете код лишней информацией. Посмотри на свои вызовы функций. Через них же невозможно продраться.


Как вы думаете, а такой вид ввызова будет выглядить лучше:
function( in_( InShort ), in_ref_( InBase ), in_( &InLong ),
          in_out_( InOutDerived ), in_out_( &InOutString ),
          out_( OutInteger ), out_( &OutFloat ) );

для такого объявления функции:
function( in< short > InShort , in< Base& > InBase, in< long* > InLong,
          in_out< Base > InOutBase, in_out< std::string* > InOutString,
          out< int > OutInteger, out< float* > OutFloat );

?
Re[3]: Реализация IN, IN-OUT и OUT параметров функций
От: Аноним  
Дата: 18.09.11 07:46
Оценка: 12 (1) +1 -1
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

GRF>Спасибо за ваше мнение. Я действительно пишу на С++ довольно короткое время — всего 1 год, до этого я писал на Java. Идея ввести IN, IN-OUT и OUT параметры вначале мне тоже не понравилась, и в начале мы хотели ввести параметры просто как define-ы. Но решающим для меня доводом от коллег было то, что новичкам будет легче понять уже существующий код, если ввести такие "подсказки". Я пошел немного дальше и решил возложить проверку параметров также на компилятор.


Да пожалуйста. Вы главное, постарайтесь понять, о чем я вам говорю. Я пишу на C++ 7 лет, профессионально и большие проекты, я тим-лидер и архитектор.

Во-первых, если у вас трудности с пониманием концепции in/out параметров после джавы, где все параметры in, стоит самому подучиться, потренироваться на нормальных примерах, чтобы улучшить свое понимание, а не бросаться переделывать язык.

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

На вопрос "позволяет ли язык C++ добавлять новые языковые конструкции?" ответ будет один: НЕТ. Нет, язык C++ не предназначен его создателями для расширения и введения новых правил типа указания входных параметров. То, что вы пытаетесь сделать — это просто уродливый хак. Вот почему-то те, кто пишет на джаве не пытаются делать подобных уродств. Видимо, язык C++ проклят.

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

Вы про Doxygen слышали? Пишите нормальные комментарии, а не разводите порнографию, честное слово.
Re[2]: Реализация IN, IN-OUT и OUT параметров функций
От: MasterZiv СССР  
Дата: 18.09.11 11:45
Оценка: 1 (1)
On 16.09.2011 21:06, Аноним 966 wrote:

>

> Я за такое избил бы коллегу клавиатурой. Это называется "синдром засирания всего
> кода ради ничтожной цели". Эта болезнь часто поражает начинающих программистов
> на C++ — неумение оценивать отношение важности задачи и сложности решения,
> сосредоточенность на второстепенных вещах, а также на коде вместо самой задачи.
> У меня тоже было что-то подобное.

Ну, в защиту топикстартера хочу сказать, что мы тоже такое делаем. Главное
отличие -- ДЛЯ ЧЕГО.

Мы это делаем для гарантированно правильных выховов хранимых процедур на сервере
БД. Для вызовов генерируются С++-ые классы-proxy, содержащие нужные
функции, и вызовы производятся только через них. При вызове контролируется
тип каждого параметра, имя параметра, и что он помечен как входной, или
входной и выходной.

Но прикол тут как раз в том, что кравивость и удобнойть такого вызова нам
НЕ НУЖНА -- эти вызовы и с, и без этого некрасивы, громоздки и уродливы
(ну нет передачи в С++ параметров по имени, ну что ж поделать).

Поэтому такие шаблоны вызовов очень полезны.

Но вставлять это ВО ВСЕХ МЕСТАХ -- это безумие.

Лучше переработать дизайн, чтобы все параметры были входными, а возврат
шёл только через значение. Тут это можно сделать, в отличие от вызовов
БД, там надо экономить round trip-ы.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Реализация IN, IN-OUT и OUT параметров функций
От: MasterZiv СССР  
Дата: 18.09.11 11:46
Оценка:
On 16.09.2011 23:10, Galiulin Rishat Faimovich wrote:

>

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

Интересно, как же ты эту проблему на Java-то решал.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: Реализация IN, IN-OUT и OUT параметров функций
От: MasterZiv СССР  
Дата: 18.09.11 11:52
Оценка: 2 (2) +1
On 18.09.2011 11:46, Аноним 966 wrote:

> Во-первых, если у вас трудности с пониманием концепции in/out параметров после

> джавы, где все параметры in, стоит самому подучиться, потренироваться на
> нормальных примерах, чтобы улучшить свое понимание, а не бросаться переделывать
> язык.

В Java можно передавать параметры по ссылке (собственно, стандартный способ
передачи объектов) и если ссылка не константная, то её можно менять в
принимающем методе. Это полный аналог IN_OUT.

> На вопрос "позволяет ли язык C++ добавлять новые языковые конструкции?" ответ

> будет один: НЕТ. Нет, язык C++ не предназначен его создателями для расширения и
> введения новых правил типа указания входных параметров. То, что вы пытаетесь
> сделать — это просто уродливый хак. Вот почему-то те, кто пишет на джаве не
> пытаются делать подобных уродств. Видимо, язык C++ проклят.

Да почему же уродливый хак ? Нормально всё. Только соотношение целей и
накладухи не выдерживает никакой критики.

Собственно, правильно оформленные сигнатуры методов и фукнций -- всё, что надо
для этого в С++.

> В языке C++ НЕТ синтаксиса указания выходных параметров, как в C#. Попытки


Есть, неконстантная ссылка, указатель на неконстанту.
И есть входных параметров -- константная ссылка либо по значению.
Как-то странно это слышать после ваших 7-ми лет.
Posted via RSDN NNTP Server 2.1 beta
Re[4]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 18.09.11 13:15
Оценка:
Здравствуйте, Аноним, Вы писали:

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


GRF>>Спасибо за ваше мнение. Я действительно пишу на С++ довольно короткое время — всего 1 год, до этого я писал на Java. Идея ввести IN, IN-OUT и OUT параметры вначале мне тоже не понравилась, и в начале мы хотели ввести параметры просто как define-ы. Но решающим для меня доводом от коллег было то, что новичкам будет легче понять уже существующий код, если ввести такие "подсказки". Я пошел немного дальше и решил возложить проверку параметров также на компилятор.


А>Да пожалуйста. Вы главное, постарайтесь понять, о чем я вам говорю. Я пишу на C++ 7 лет, профессионально и большие проекты, я тим-лидер и архитектор.


А>Во-первых, если у вас трудности с пониманием концепции in/out параметров после джавы, где все параметры in, стоит самому подучиться, потренироваться на нормальных примерах, чтобы улучшить свое понимание, а не бросаться переделывать язык.


А>Во-вторых, вы (и не только вы, а многие) почему-то считают, что язык C++ можно расширять, добавляя свои правила и новые синтаксические конструкции.


А>На вопрос "позволяет ли язык C++ добавлять новые языковые конструкции?" ответ будет один: НЕТ. Нет, язык C++ не предназначен его создателями для расширения и введения новых правил типа указания входных параметров. То, что вы пытаетесь сделать — это просто уродливый хак. Вот почему-то те, кто пишет на джаве не пытаются делать подобных уродств. Видимо, язык C++ проклят.


А>В языке C++ НЕТ синтаксиса указания выходных параметров, как в C#. Попытки ввести эту возможность с помощью шаблонных и других конструкций — это просто уродование программы. Надо с этим смириться, так как, уверяю вас, это совершенно незначительная проблема, не приводящая к каким-либо последствиям в проектах любого размера и сложности.


А>Вы про Doxygen слышали? Пишите нормальные комментарии, а не разводите порнографию, честное слово.


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

MZ>On 16.09.2011 23:10, Galiulin Rishat Faimovich wrote:


>>

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

MZ>Интересно, как же ты эту проблему на Java-то решал.


Никогда не решал такую проблему на Java.
Re[5]: Реализация IN, IN-OUT и OUT параметров функций
От: Аноним  
Дата: 18.09.11 13:37
Оценка:
Здравствуйте, MasterZiv, Вы писали:

>> В языке C++ НЕТ синтаксиса указания выходных параметров, как в C#. Попытки


MZ>Есть, неконстантная ссылка, указатель на неконстанту.

MZ>И есть входных параметров -- константная ссылка либо по значению.
MZ>Как-то странно это слышать после ваших 7-ми лет.

В C# есть два кейворда — out и ref. В C++ — нет. Понятно, или тебе привести научную работу с обоснованиями и списком ссылок?
Re[3]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 18.09.11 13:40
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>On 16.09.2011 21:06, Аноним 966 wrote:


>>

>> Я за такое избил бы коллегу клавиатурой. Это называется "синдром засирания всего
>> кода ради ничтожной цели". Эта болезнь часто поражает начинающих программистов
>> на C++ — неумение оценивать отношение важности задачи и сложности решения,
>> сосредоточенность на второстепенных вещах, а также на коде вместо самой задачи.
>> У меня тоже было что-то подобное.

MZ>Ну, в защиту топикстартера хочу сказать, что мы тоже такое делаем. Главное

MZ>отличие -- ДЛЯ ЧЕГО.

MZ>Мы это делаем для гарантированно правильных выховов хранимых процедур на сервере

MZ>БД. Для вызовов генерируются С++-ые классы-proxy, содержащие нужные
MZ>функции, и вызовы производятся только через них. При вызове контролируется
MZ>тип каждого параметра, имя параметра, и что он помечен как входной, или
MZ>входной и выходной.

MZ>Но прикол тут как раз в том, что кравивость и удобнойть такого вызова нам

MZ>НЕ НУЖНА -- эти вызовы и с, и без этого некрасивы, громоздки и уродливы
MZ>(ну нет передачи в С++ параметров по имени, ну что ж поделать).

MZ>Поэтому такие шаблоны вызовов очень полезны.


MZ>Но вставлять это ВО ВСЕХ МЕСТАХ -- это безумие.


MZ>Лучше переработать дизайн, чтобы все параметры были входными, а возврат

MZ>шёл только через значение. Тут это можно сделать, в отличие от вызовов
MZ>БД, там надо экономить round trip-ы.

Спасибо за ваше мнение. Хотелось бы точнее понять, где стоит использовать эту нотацию, а где не нужно такого делать.
Изложите, пожалуйста, в виде правил.
Re[4]: Реализация IN, IN-OUT и OUT параметров функций
От: rumit7  
Дата: 18.09.11 15:57
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Да пожалуйста. Вы главное, постарайтесь понять, о чем я вам говорю. Я пишу на C++ 7 лет, профессионально и большие проекты, я тим-лидер и архитектор.

А>Во-первых, если у вас трудности с пониманием концепции in/out параметров после джавы, где все параметры in, стоит самому подучиться, потренироваться на нормальных примерах, чтобы улучшить свое понимание, а не бросаться переделывать язык.

Прикольно, значит по Вашему у человека, который сумел реализовать всю эту шаблонную магию не достаточно практики с указателями/ссылками? Вы вообще как себе это представляете? Вы понимаете, что человек который не понимает как работают указатели/ссылки не пойдет дальше и не начнет реализовывать дополнительные средства?

А>Во-вторых, вы (и не только вы, а многие) почему-то считают, что язык C++ можно расширять, добавляя свои правила и новые синтаксические конструкции.


Вы имеете ввиду:
1) "Move Constructors" By Andrei Alexandrescu;
2) "Lambda: unnamed functions in C++" by Jaakko Järvi, Gary Powell;
и многих других?

А>На вопрос "позволяет ли язык C++ добавлять новые языковые конструкции?" ответ будет один: НЕТ. Нет, язык C++ не предназначен его создателями для расширения и введения новых правил типа указания входных параметров. То, что вы пытаетесь сделать — это просто уродливый хак. Вот почему-то те, кто пишет на джаве не пытаются делать подобных уродств. Видимо, язык C++ проклят.


А мужики то не знают!
Re[5]: Реализация IN, IN-OUT и OUT параметров функций
От: MasterZiv СССР  
Дата: 18.09.11 17:40
Оценка:
On 09/18/2011 05:18 PM, Galiulin Rishat Faimovich wrote:

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

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

А что ж на плюсах-то припёрло ?
Одинаковые же проблемы.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: Реализация IN, IN-OUT и OUT параметров функций
От: Аноним  
Дата: 18.09.11 22:58
Оценка: 1 (1)
Здравствуйте, rumit7, Вы писали:

R>Прикольно, значит по Вашему у человека, который сумел реализовать всю эту шаблонную магию не достаточно практики с указателями/ссылками? Вы вообще как себе это представляете? Вы понимаете, что человек который не понимает как работают указатели/ссылки не пойдет дальше и не начнет реализовывать дополнительные средства?


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

Но через пару лет у меня это как-то прошло, и я пришел к KISS и бритве Оккама.

А>>Во-вторых, вы (и не только вы, а многие) почему-то считают, что язык C++ можно расширять, добавляя свои правила и новые синтаксические конструкции.


R>Вы имеете ввиду:

R>1) "Move Constructors" By Andrei Alexandrescu;
R>2) "Lambda: unnamed functions in C++" by Jaakko Järvi, Gary Powell;
R>и многих других?

Ну, во-первых, г-н Александреску — это, хоть и умный мужик и ценный кадр, но известный порнограф, вклад которого в создание шаблонных порнобиблиотек трудно переоценить.

Во-вторых, что-то из подобных трудов я и сам использую, придерживаясь правила "все хорошо в меру" и, опять же, KISS и бритвы Оккама.

В-третьих, вы понимаете разницу между синтаксической конструкцией, поддерживаемой компилятором, и самопальной пародией на такую конструкцию из говна и палок. Например, лямбды в C++ 11 и Boost.Lambda. Разницу надо объяснять? Язык, в котором поддерживается расширение синтаксиса — это, например, любимый на этом форуме Немерле. Вот там — совсем другое дело, потому что язык специально для этих целей и делался.

Ну и, наконец, пример топикстартера — это случай, когда определенно цель не стоит средств, он ни в какие ворота не лезет.

А>>На вопрос "позволяет ли язык C++ добавлять новые языковые конструкции?" ответ будет один: НЕТ. Нет, язык C++ не предназначен его создателями для расширения и введения новых правил типа указания входных параметров. То, что вы пытаетесь сделать — это просто уродливый хак. Вот почему-то те, кто пишет на джаве не пытаются делать подобных уродств. Видимо, язык C++ проклят.


R>А мужики то не знают!


Мне жаль этих мужиков. Кругозор надо расширять.
Re[6]: Реализация IN, IN-OUT и OUT параметров функций
От: alexeiz  
Дата: 18.09.11 23:09
Оценка:
Здравствуйте, Аноним, Вы писали:

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


Самому себе польстить — святое дело!
Re[7]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 19.09.11 05:49
Оценка: 2 (1)
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

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


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

std::unique_ptr< A > p2( new A );
sink2( in< std::unique_ptr< const A > >( std::move( std::unique_ptr< const A >( std::move(p2) ) ) ) );


Но, я надеюсь, никому не придет в голову сказать что этот ужас читать легче чем

std::unique_ptr< A > p1( new A );
sink1( std::move( p1 ) );


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

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


После этого можно будет вспомнить о существовании rvalue-references и необходимости поддерживать perfect forwarding.
Re[7]: Реализация IN, IN-OUT и OUT параметров функций
От: k.o. Россия  
Дата: 19.09.11 06:03
Оценка:
Здравствуйте, Galiulin Rishat Faimovich, Вы писали:

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


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


GRF>>>>>В нашей нотации необходимо несколько изменить вызов и определение:


KO>>>>И получить другое поведение? Нет уж, так не пойдёт, боюсь, небольшим изменением тут не отделаться.


GRF>>>Нет вы получите именно то поведение которое желаете, попробуйте.


KO>>Но позвольте, конструкторы класса 'in' принимают константную ссылку на значение аргумента, мне же нужно передавать аргумент по-значению, для unique_ptr передача по константной ссылке и передача по значению это две большие разницы. Впрочем, я попробовал, как и ожидалось, "эквивалентный" код успешно компилируется, там где оригинальный (как и задумывалось) приводит к ошибке компиляции.


KO>>>>>>и не всегда применим:


KO>>>>>>
KO>>>>>>MyType z = in<MyType&>(in<MyType&>(a) + in<MyType&>(in<MyType&>(b) * in<MyType&>(c)));
KO>>>>>>


KO>>>>>>во что это превратится с использованием expression templates я даже думать не хочу, впрочем, как я понял, некоторым такой вариант кажется более читабельным по сравнению с


GRF>>>>>Мы и не планировали что in, in_out и out будут так применяться .


KO>>>>А как же ещё им применяться? Входные параметры есть, почему их не надо помечать? Впрочем, я, кажется, понимаю: благодаря удачным названиям функций способ использования передаваемых параметров очевиден, может, тогда, вместо изобретения велосипедов, стоит давать более удачные названия функциям?


GRF>>>Например в определении функции так:

GRF>>>
GRF>>>void function( in< MyType& > a, in< MyType& > b, in< MyType& > c )
GRF>>>{
GRF>>>   MyType z = a() + b() * c();
GRF>>>}
GRF>>>


KO>>
KO>>MyType operator+( in< MyType& > lhs, in< MyType& > rhs )
KO>>{
KO>>    return ...;
KO>>}
KO>>


KO>>что я делаю не так?


GRF>>>Для того чтобы писать:

GRF>>>
GRF>>>MyType z = a + b * c;
GRF>>>

GRF>>>надо будет перегрузить операторы.

KO>>ну да, надо будет, это вы к чему сказали?


GRF>Я имел ввиду что надо будет добавить операторы в specification.hpp .


GRF>Чтобы заработал Ваш пример оператора надо написать так:

GRF>
GRF>MyType operator+( in< MyType& > lhs, in< MyType& > rhs )
GRF>{
GRF>    return lhs() + rhs();
GRF>}
GRF>


А откуда, при вашем подходе, возьмётся функция 'MyType operator+( const MyType&, const MyType& rhs )'? Если уж быть последовательным, то реализация будет выглядеть как-то так:
MyType operator+( in< MyType& > lhs, in< MyType& > rhs )
{
    MyType result(lhs()); // или, если конструктор копии мы тоже запрещаем: MyType result(lhs);
    result += rhs; // operator+=(in< MyType &>)
    return result;
}


В любом случае, мы получаем уже упомянутый ужас:
MyType z = in<MyType&>(in<MyType&>(a) + in<MyType&>(in<MyType&>(b) * in<MyType&>(c)));


Или, может, предлагается использовать такой подход не для всех функций? Тогда, пожалуй, стоит перечислить сценарии, в которых предполагается это использовать, в исходном сообщении об этом ничего не было сказано.
Re[8]: Реализация IN, IN-OUT и OUT параметров функций
От: Galiulin Rishat Faimovich Узбекистан  
Дата: 19.09.11 11:27
Оценка:
Здравствуйте, k.o., Вы писали:

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


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


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


KO>
KO>std::unique_ptr< A > p2( new A );
KO>sink2( in< std::unique_ptr< const A > >( std::move( std::unique_ptr< const A >( std::move(p2) ) ) ) );
KO>


KO>Но, я надеюсь, никому не придет в голову сказать что этот ужас читать легче чем


KO>
KO>std::unique_ptr< A > p1( new A );
KO>sink1( std::move( p1 ) );
KO>


Да, действительно выглядит плохо . Но можно немного короче
std::unique_ptr< A > p2( new A );
sink2( in< std::unique_ptr< const A > >( std::unique_ptr< const A >( std::move( p2 ) ) ) );


Вот альтернативный вариант 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 const Type&() const
    {
        return 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 ) {}

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

    /**
     * input parameter value
     */
    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_( 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_;
    }

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_( const 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 */


C ним нужно писать так:
std::unique_ptr< A > p2( new A );
sink2( in_( std::unique_ptr< const A >( std::move( p2 ) ) ) );



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>


А где здесь проблема? Можете подробнее? У меня вроде вот этот код работает
void sink( in< std::unique_ptr< const A > > arg)
{
}

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



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


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

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


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


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


GRF>>>>>>В нашей нотации необходимо несколько изменить вызов и определение:


KO>>>>>И получить другое поведение? Нет уж, так не пойдёт, боюсь, небольшим изменением тут не отделаться.


GRF>>>>Нет вы получите именно то поведение которое желаете, попробуйте.


KO>>>Но позвольте, конструкторы класса 'in' принимают константную ссылку на значение аргумента, мне же нужно передавать аргумент по-значению, для unique_ptr передача по константной ссылке и передача по значению это две большие разницы. Впрочем, я попробовал, как и ожидалось, "эквивалентный" код успешно компилируется, там где оригинальный (как и задумывалось) приводит к ошибке компиляции.


KO>>>>>>>и не всегда применим:


KO>>>>>>>
KO>>>>>>>MyType z = in<MyType&>(in<MyType&>(a) + in<MyType&>(in<MyType&>(b) * in<MyType&>(c)));
KO>>>>>>>


KO>>>>>>>во что это превратится с использованием expression templates я даже думать не хочу, впрочем, как я понял, некоторым такой вариант кажется более читабельным по сравнению с


GRF>>>>>>Мы и не планировали что in, in_out и out будут так применяться .


KO>>>>>А как же ещё им применяться? Входные параметры есть, почему их не надо помечать? Впрочем, я, кажется, понимаю: благодаря удачным названиям функций способ использования передаваемых параметров очевиден, может, тогда, вместо изобретения велосипедов, стоит давать более удачные названия функциям?


GRF>>>>Например в определении функции так:

GRF>>>>
GRF>>>>void function( in< MyType& > a, in< MyType& > b, in< MyType& > c )
GRF>>>>{
GRF>>>>   MyType z = a() + b() * c();
GRF>>>>}
GRF>>>>


KO>>>
KO>>>MyType operator+( in< MyType& > lhs, in< MyType& > rhs )
KO>>>{
KO>>>    return ...;
KO>>>}
KO>>>


KO>>>что я делаю не так?


GRF>>>>Для того чтобы писать:

GRF>>>>
GRF>>>>MyType z = a + b * c;
GRF>>>>

GRF>>>>надо будет перегрузить операторы.

KO>>>ну да, надо будет, это вы к чему сказали?


GRF>>Я имел ввиду что надо будет добавить операторы в specification.hpp .


GRF>>Чтобы заработал Ваш пример оператора надо написать так:

GRF>>
GRF>>MyType operator+( in< MyType& > lhs, in< MyType& > rhs )
GRF>>{
GRF>>    return lhs() + rhs();
GRF>>}
GRF>>


KO>А откуда, при вашем подходе, возьмётся функция 'MyType operator+( const MyType&, const MyType& rhs )'? Если уж быть последовательным, то реализация будет выглядеть как-то так:

KO>
KO>MyType operator+( in< MyType& > lhs, in< MyType& > rhs )
KO>{
KO>    MyType result(lhs()); // или, если конструктор копии мы тоже запрещаем: MyType result(lhs);
KO>    result += rhs; // operator+=(in< MyType &>)
KO>    return result;
KO>}
KO>


Если нет ни
MyType ::operator+( const MyType& lhs, const MyType& rhs );

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

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

?


KO>В любом случае, мы получаем уже упомянутый ужас:

KO>
KO>MyType z = in<MyType&>(in<MyType&>(a) + in<MyType&>(in<MyType&>(b) * in<MyType&>(c)));
KO>


Зачем писать:
MyType z = in<MyType&>(in<MyType&>(a) + in<MyType&>(in<MyType&>(b) * in<MyType&>(c)));

когда можно писать:
MyType z = a() + b() * c();

?

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


in, in_out и out должны использваться в теле функций или в вызовах функций
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.