Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > устраивает ли Вас препроцессор С++?


Автор: Jcs 17.5.2007, 18:57
Здравствуйте, ни у кого не возникало ощущения куцести плюсового препроцессора? У меня, например, периодически возникают случаи, когда его возможностей определенно хватает. Вот один из них. Стандартный случай, когда нужны методы с различными правам доступа ко внутренним переменным. Приходится писать кучу одинакового кода. Данный пример для двух переменных, и то разница уже видна, а что будет когда их число приблизится, например, к 10?
Код

class model
{
    int property0_;
    double propety_1;

public:
    int& property0()
    {return property0_;}

    double& property1()
    {return property1_;}

    const int& property0() const
    {return property0_;}

    const double& property1() const
    {return property2_;}
};

class model
{
    int property0_;
    double propery1_;
public:
    %for_each_member
    %{
        %member_type& %member_name()
        {return %member_name;}

        const %member_type %member_name() const
        {return %member_name;}
    %}
};

Этот случай не первый и не единственный, хотелось бы послушать общество. Заранее спасибо

Автор: MAKCim 17.5.2007, 19:24
в целом хватает
хотя препроцессор GAS (Gnu Assembler) по-лучше будет
я бы добавил
1. Перегрузку макрофункций
Код

#define GET(a) (a)
#define GET(a, b) ((a) + (b))
...

2. Циклы 
Код

int array[SIZE] = {
#repeat SIZE - 1
    __ITERATION__,
#endrep
    SIZE - 1 };

где __ITERATION__ - номер текущей итерации (0, 1, 2, ...)
3. Внутренние макродирективы
Код

#repeat SIZE - 1
    #if __ITERATION__ != 50
        __ITERATION__
    #else
        0
    #endif
#endrep

Автор: JackYF 17.5.2007, 19:33
Совершенству нет предела.
В целом - устраивает, для меня это далеко не самая важная часть программирования.
Добавить функциональность, о которой говорится в начале темы - можно, конечно... вот только, для начала, предложите для нее синтаксис.

Автор: nickless 17.5.2007, 19:34
ИМХО возможностей у препроцессора вполне достаточно, и даже они обычно не используются, потому что в С++ есть много способов сделать то же самое проще/лучше/удобнее. См. например шаблоны.
Насчет твоего примера, можно сделать например так:
Код
#define ACCESSOR(type,name)     type& name() { return name##_; } \
                                const type & name() const { return name##_; }

class model
{
public:
    ACCESSOR( int, property0 )
    ACCESSOR( double, property1 )
private:
    int property0_;
    double property1_;
};


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

Есть еще примеры?

Автор: Daevaorn 17.5.2007, 19:35
Проще пропускать сорсы через какой-нибудь шаблонизатор, чем ждать пока сделают изменения в препроцессоре. Например так как поступает Trolltech.

Автор: JackYF 17.5.2007, 19:36
Цитата(JackYF @  17.5.2007,  19:33 Найти цитируемый пост)
предложите для нее синтаксис. 


Это же надо, 
MAKCim, Максим прочитал мои мысль, пока я ее писал...


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

Автор: Daevaorn 17.5.2007, 19:37
Цитата(Jcs @  17.5.2007,  19:57 Найти цитируемый пост)
 Данный пример для двух переменных, и то разница уже видна, а что будет когда их число приблизится, например, к 10?

Кстати, это пример плохого дизайна, а не слобости препроцессора;)

Автор: Hurricane 17.5.2007, 19:44
Daevaorn, ты тоже мыслечитатель?  smile 

Цитата(Daevaorn @  17.5.2007,  11:37 Найти цитируемый пост)
Кстати, это пример плохого дизайна, а не слобости препроцессора;) 


Первая мысль была именно такая.

Добавлено через 4 минуты и 37 секунд
Кстати, а почему нет варианта "В препроцессоре и так много лишнего, сократить до минимума". А то начинаешь юзать всякие темплейтные min/max/swap, а какой-то умник их уже через дефайны переопределил. И начинаешь чесать репу, лихорадочно соображая что сделал не так.

Автор: MAKCim 17.5.2007, 19:50
 smile 
Daevaorn, 
прикольное число сообщений у тебя 1234  smile 

Автор: maxim1000 17.5.2007, 20:57
ИМХО, основной недостаток препроцессора в том, что он не разбирается в том, что обрабатывает (ну разве что не трогает строки и не обрабатывает max в max1)
в этом смысле шаблоны более "встроены в язык", хотя и возможностей местами поменьше
так что, возможно, было бы неплохо, как-то сближать эти два инструмента...

Автор: nerezus 17.5.2007, 21:19
Собственно шаблоны и есть аналогом препроцессора, просто шаблоны не являются препроцессором по определению )

Автор: jonie 17.5.2007, 23:07
о чем Вы?! вам мало "приятных" и незаметных вещей что дает вам препроцессор?)
Код

#define max(a,b) a<b?b:a         //ну, конечно, сейчас все начнут говорить что мол надо скобок больше) это пример только
....
int a=20;
int b=30;
int c = max(a+=5,b);  //интересно что это даст ....

кстати можете себя проверить.. код даст 50 (а вот на старых компиляторах может дать и не 50)...
смех смехом а я как-то часа 4 искал такую "ошибку" (не в своем коде).... уж никак не пологал что сделан будет макрос... вот чего в голву не пришло, того не пришло)
---------------------
все эти намудреные препроцессорные директивы выливаются в полную мешанину и панику при отладке (нее дай вам столкнуться с ошибкой неявной в большом макросе)...
------------------
Цитата

1. Перегрузку макрофункций
inline - функции чем не устраивают?!
Цитата

2. Циклы 

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

----------------
в общем говоря о "плюсах" не стоит забывать и о минусах....а хочется гуд препроцессор какй вам надо так есть perl ....)) пишите и травите на свои исходники....

Автор: Jcs 18.5.2007, 10:55
nickless, 
Предложенный вами вариант, конечно, упрощает, но тем не менее нужно для каждого члена класса писать вызов макроса.
Насчет шаблонов полностью согласен, но они не обеспечивают возможность перечисления членов структуры (или я не знаю как это сделать).
Еще один случай, когда это было бы удобно. Например, есть текстовый файл, из которого нужно считать структуру. В случае возможности перечисления можно было бы написать подобный код (данный пример призван показать полезность перечисления, поэтому, пожалуйста, не обращайте внимания на контроль ошибок и проч.):
Код

struct config
{
    int param0,param1;
    float param2,param3;
    double param4,param5;
};

template<ParamType> 
    void read_param(file& ifile,const char* param_name,ParamType& param_ref);

template<StructToRead>
    void read_config(StructToRead& struct_ref,const char* file_name)
{
    file ifile(file_name,IO_read_mode);
    
    %for_each_member_of(StructToRead)
    %{    
        read_param(ifile,"%member_name",struct_ref.%member_name);
    %}
}

Автор: Любитель 18.5.2007, 10:58
Цитата(Hurricane @  17.5.2007,  19:44 Найти цитируемый пост)
Кстати, а почему нет варианта "В препроцессоре и так много лишнего, сократить до минимума". 

Кстати вариант то правильный smile

Если хочется поизвращаться - советую посмотреть ещё на boost::preprocessor. Я толком не смотрел, но если не ошибаюсь циклы там есть. Правда, наверно, с ограниченным количеством итераций (просто не представляю как сделать, юзаю лишь существующие возможности, по-другому).

А вообще шаблоны для кого придумывали? smile

Автор: Jcs 18.5.2007, 11:15
Наверное, вопрос был поставлен не совсем корректно. Правильней было бы спросить - устраивают ли Вас возможности метапрограммирования с С++? Тогда сюда автоматом войдут и шаблоны, и макро. Думаю функциональность шаблонов тоже есть куда расширять. Например в книге "шаблоны. Спавочник пользователя" говорится о возможности включения именованных аргументов шаблонов. Я бы еще добавил частичную специализацию по количеству шаблонных аргументов.

Автор: MAKCim 18.5.2007, 20:24
Цитата(jonie @  17.5.2007,  23:07 Найти цитируемый пост)
inline - функции чем не устраивают?!

ты дашь гарантию, что они будут inline?  smile 
Цитата(jonie @  17.5.2007,  23:07 Найти цитируемый пост)
приведенный пример хоть и встречается, но редко....тем более что если массив такой локальный то ничего хорошего не будет из той инициализации ...

пример надуманный (только, чтобы идентифицировать конструкцию)

Автор: jonie 19.5.2007, 00:36
Цитата

ты дашь гарантию, что они будут inline?   
я не писал компилятор (всмысле писал когда-то как курсовик), но то не о том)=> никаких гарантия я дать не могу, однако хоть стандарт и не оговаривает что inline будут inline, но компилятору я пологаю можно указать чтобы он делал принудилово... опять же как реализовано.
Да и в общем случаем "оно вам надо" ? Обычно большой оптимизации по скорости не будет (время вызова скажем __fastcall функции << времени  цикла (или иной, не подходящей под определение inline, как посчитает (если посчитает) умный компилятор) , т.о. этим временем можно пренебречь. Безусловно, существуют задачи, в которых размер стека жестко ограничен (кодинг железа, я пологаю),но с таким вещаями я не знаком и думаю там есть средства....
Цитата

Добавлено через 4 минуты и 37 секунд
Кстати, а почему нет варианта "В препроцессоре и так много лишнего, сократить до минимума". А то начинаешь юзать всякие темплейтные min/max/swap, а какой-то умник их уже через дефайны переопределил. И начинаешь чесать репу, лихорадочно соображая что сделал не так.
упс, когда писал свой пост пропустил это, но, как минимум я не один так считаю) и то гуд... это - мой вариант выбора.

Автор: MAKCim 19.5.2007, 08:13
Цитата(jonie @  19.5.2007,  00:36 Найти цитируемый пост)
но компилятору я пологаю можно указать чтобы он делал принудилово... опять же как реализовано.

вот именно, переносимость будет -> 0
Цитата(jonie @  19.5.2007,  00:36 Найти цитируемый пост)
Да и в общем случаем "оно вам надо" ? Обычно большой оптимизации по скорости не будет (время вызова скажем __fastcall функции << времени  цикла (или иной, не подходящей под определение inline, как посчитает (если посчитает) умный компилятор) , т.о. этим временем можно пренебречь.

макросы нужны не только для эмуляции inline

Автор: JackYF 19.5.2007, 12:12
ИМХО, есть несколько принципиальных случаев/моментов, когда макросы незаменимы в принципе. То есть аналогию с помощью чисто языковых конструкций построить не удастся.
Есть еще группа случаев, когда удастся, но слишком дорогой ценой (размер или производительность пострадают).
В остальных случаях можно использовать [шаблонные ][inline ]функции.

Автор: vinter 19.5.2007, 13:02
а смысл данного опроса?  допустим мне не нравится то то, то то. Кто то согласится, кто то нет. Но это не изменит ничего. Какой-то бесполезный топик. извиняюсь за оффтоп

Автор: Любитель 19.5.2007, 14:02
Цитата(Jcs @  18.5.2007,  11:15 Найти цитируемый пост)
Правильней было бы спросить - устраивают ли Вас возможности метапрограммирования с С++?

Вот, если так - поддержу. Только не макросы.

MAKCim, вот в реальной жизни все твои примеры с циклами и перегрузкой для макросов когда-нибудь хотелось использовать (я, конечно, про плюсы)? Сомневаюсь, если честно.

Цитата(MAKCim @  19.5.2007,  08:13 Найти цитируемый пост)
макросы нужны не только для эмуляции inline 

Не спорю.

Цитата(MAKCim @  18.5.2007,  20:24 Найти цитируемый пост)
пример надуманный 

Вот именно. Можешь представить практические примеры (точнее - похожие на практические), где такое можно было бы красиво использовать?

Единственное, что кстати не помешает в препроцессоре - области видимости макросов (банальные блоки). Но это вроде и так обещали...

Цитата(vinter @  19.5.2007,  13:02 Найти цитируемый пост)
а смысл данного опроса?  допустим мне не нравится то то, то то. Кто то согласится, кто то нет. Но это не изменит ничего. Какой-то бесполезный топик. извиняюсь за оффтоп 

Ну, я бы не сказал, что бесполезный. Может ничего и не изменит (99,99999 %), но поговорить интересно smile

Автор: MAKCim 19.5.2007, 15:47
Цитата(Любитель @  19.5.2007,  14:02 Найти цитируемый пост)
MAKCim, вот в реальной жизни все твои примеры с циклами и перегрузкой для макросов когда-нибудь хотелось использовать (я, конечно, про плюсы)? Сомневаюсь, если честно.

хотелось пару раз
Цитата(Любитель @  19.5.2007,  14:02 Найти цитируемый пост)
Можешь представить практические примеры (точнее - похожие на практические), где такое можно было бы красиво использовать?

Код

#define SYMBOL(name, value)    \
    __asm__(#name" = %0" : : "I" (value))

static void __generate() {
#repeat COUNT
    #ifdef value#__ITERATION__
        SYMBOL(value#__ITERATION__, value#__ITERATION__);
    #endif
#endrep
}

хотя пример тоже какой-то нереальный получился  smile 

Автор: Любитель 19.5.2007, 16:16
Цитата(MAKCim @  19.5.2007,  15:47 Найти цитируемый пост)
хотя пример тоже какой-то нереальный получился  

 smile По-моему, совсем нереальный. Препроцессор для асма - это совсем другой вопрос, ибо там шаблонов нет smile Ввиду полнейшей непортируемости вышенаписанного кода - тяжело говорить про расширение стандартного препроцессор для этого...

Автор: MAKCim 19.5.2007, 16:42
Любитель, 
в С тоже нет шаблонов  smile 
а так подумаю на досуге над примером... реальным  smile 
кстати, если ты с make знаком, мне там очень нравятся функции типа
$(foreach)
...
можно было бы писать такое
Код

#list DIRS a, b, c, d, e, f, g
#foreach DIRS
        #include #__CURRENT__
#endeach

 smile 

Автор: nerezus 19.5.2007, 17:29
Цитата

можно было бы писать такое
 А мне кажестся, что на уровне синтаксиса это было бы удобнее $)

Автор: Mayk 19.5.2007, 17:31
Цитата(Любитель @  19.5.2007,  18:02 Найти цитируемый пост)

MAKCim, вот в реальной жизни все твои примеры с циклами и перегрузкой для макросов когда-нибудь хотелось использовать (я, конечно, про плюсы)? Сомневаюсь, если честно.

В G++  схожая техника используется для  эмуляции Variadic Templates(google).  

Цитата(/usr/include/c++/4.0/tr1/tuple)

.....
#define _SHORT_REPEAT
#define _GLIBCXX_REPEAT_HEADER <tr1/tuple_iterate.h>
#include <tr1/repeat.h>
#undef _GLIBCXX_REPEAT_HEADER
#undef _SHORT_REPEAT


А вот самое интересное:
Цитата(/usr/include/c++/4.0/tr1/tuple_iterate.h)

.....
/// @brief class tuple_size
template<_GLIBCXX_TEMPLATE_PARAMS>
  struct tuple_size<tuple<_GLIBCXX_TEMPLATE_ARGS> >
  { static const int value = _GLIBCXX_NUM_ARGS; };


По топику --- для генерации сложных хедеров использую питон.

Автор: bsa 19.5.2007, 18:53
Цитата(MAKCim @ 19.5.2007,  16:42)
Любитель, 
в С тоже нет шаблонов  smile 
а так подумаю на досуге над примером... реальным  smile 
кстати, если ты с make знаком, мне там очень нравятся функции типа
$(foreach)
...
можно было бы писать такое
Код

#list DIRS a, b, c, d, e, f, g
#foreach DIRS
        #include #__CURRENT__
#endeach

 smile

Ужас! Я на 100% уверен, найдется "профессионал", который сделает определение DIR в одном месте, а подобное использование в другом. Вот обрадуются же те, кто отлаживать возьмется (модифицировать)... smile 

Автор: JackYF 20.5.2007, 01:51
Цитата(Jcs @  18.5.2007,  10:55 Найти цитируемый пост)
но они не обеспечивают возможность перечисления членов структуры


Кстати, вот одна из нескольких дельных мыслей. Мне несколько раз этой возможности не хватало. Как замутить такое - не нашел, и сам не придумал. Можно ли?
Компилятор ведь умеет, когда составляет конструктор копирования по-умолчанию.

Автор: Hurricane 20.5.2007, 02:09
Цитата(JackYF @  19.5.2007,  17:51 Найти цитируемый пост)
Кстати, вот одна из нескольких дельных мыслей. Мне несколько раз этой возможности не хватало. Как замутить такое - не нашел, и сам не придумал. Можно ли?
Компилятор ведь умеет, когда составляет конструктор копирования по-умолчанию.


Что будем перечислять для public, protected, private мемберов наследуемого класса в С++? Я бы понял, если бы это делал компилятор (конструкция языка), но препроцессор... Или препроцессор должен знать правила доступа для разных типов наследования? Или для С должен быть другой препроцессор?

Насчет foreach. В С/С++ нет контейнеров как интегральных типов данных _языка_. Они реализованы на уровне библиотек (boost, stl  и т.д.), и библиотеки поддерживают foreach (или for_each). Я не понимаю, почему это должно поддерживаться на уровне компилятора (для языка) или препроцессора. Вариант с {...in list} - это тоже частный случай контейнера, он должен каким-то образом создаться. Для каких типов данных? Это должен решать программист или препроцессор?

Сравните с Perl, где тип контейнеров - часть языка.

Автор: MAKCim 20.5.2007, 10:05
Hurricane, 
про что ты говоришь, и что я написал  smile 

Автор: JackYF 20.5.2007, 18:12
Цитата(Hurricane @  20.5.2007,  02:09 Найти цитируемый пост)
Я бы понял, если бы это делал компилятор (конструкция языка)


Да кто спорит? Компилятор, он, родимый. Главное - функциональная возможность, а не чем и через что она будет реализована.
Пускай будет конструкция языка. Просто по сути это будет "языковой препроцессор".

Цитата(Hurricane @  20.5.2007,  02:09 Найти цитируемый пост)
Насчет foreach.

А насчет for_each про контейнеры речь и не шла. См. пост MAKCimа выше.

Автор: Hurricane 20.5.2007, 19:22
Цитата(MAKCim @  20.5.2007,  02:05 Найти цитируемый пост)
Hurricane, 
про что ты говоришь, и что я написал 

Ты гарантируешь, что не найдется умник, который будет использовать это не для включения файлов, а для работы с  данными или чего-нибудь еще? Не верю.

Автор: Jcs 21.5.2007, 15:45
Hurricane, 
Для перечисления методов с различным доступом можно использовать ключевые слова (for each protected, public ..) - здесь проблем не вижу. Другой вопрос - на кого можно было бы возложить данную задачу (препроцессор или шаблоны) и стоит ли ее вообще решать. Судя по обсуждению - большинство довольствуется существующими возможностями метапрограммирования, а значит никаких нововведений в данном ключе не предвидится. Может быть это правильно, и позволит избежать появления винегрета типа c#, но, с другой стороны, если расширить функциональность (без потери в производительности, совместимости и удобстве) то наверняка появится и спрос на подобные возможности.

Автор: Hurricane 21.5.2007, 18:40
Цитата(Jcs @ 21.5.2007,  07:45)
Hurricane, 
Для перечисления методов с различным доступом можно использовать ключевые слова (for each protected, public ..) - здесь проблем не вижу. Другой вопрос - на кого можно было бы возложить данную задачу (препроцессор или шаблоны) и стоит ли ее вообще решать. Судя по обсуждению - большинство довольствуется существующими возможностями метапрограммирования, а значит никаких нововведений в данном ключе не предвидится. Может быть это правильно, и позволит избежать появления винегрета типа c#, но, с другой стороны, если расширить функциональность (без потери в производительности, совместимости и удобстве) то наверняка появится и спрос на подобные возможности.

Ключевые слова pivate, protected и т.д. не спасут - препроцессор все равно должен будет иметь представление о видимостях членов и методов классов - они объявляются все скопом в соответствующих секциях, а не каждый индивидуйно (как в С#, например). Кроме того, если класс наследуется и какой-либо из членов или методов не перегружен (используется из родительского класса) - надо ли их включать? Можно, конечно, нагородить ключевых слов для всех возможных ситуаций, но я не думаю, что это будет хорошо.

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

Ну консерватор я, консерватор!  smile 

Автор: HappyLife 21.5.2007, 18:52
Народ любит поспорить в том что всё имеет место жить, и что умные люди которые "не советуют" вовсе не умные раз "не советуют".

Автор: MAKCim 21.5.2007, 19:43
Цитата(Hurricane @  20.5.2007,  19:22 Найти цитируемый пост)
Ты гарантируешь, что не найдется умник, который будет использовать это не для включения файлов, а для работы с  данными или чего-нибудь еще? Не верю.

я ничего не гарантирую
более того, следуя твоей логике, вообще следует много от чего отказаться, потому как "найдется умник..."  smile 

Автор: Hurricane 21.5.2007, 19:50
Цитата(MAKCim @  21.5.2007,  11:43 Найти цитируемый пост)
более того, следуя твоей логике, вообще следует много от чего отказаться, потому как "найдется умник..."  


Погоди, я попробую угадать... Т.е. на самом деле - умники не находятся, сложность конструкций никак не связана с их безопасностью, и вообще, это все выдумки Hurrican'а, так?  smile 

Автор: MAKCim 21.5.2007, 19:52
Цитата(Hurricane @  21.5.2007,  19:50 Найти цитируемый пост)
Погоди, я попробую угадать... Т.е. на самом деле - умники не находятся, сложность конструкций никак не связана с их безопасностью, и вообще, это все выдумки Hurrican'а, так?

шаблоны С++ сложны? 
безопасны?

Автор: Hurricane 21.5.2007, 20:03
Цитата(MAKCim @  21.5.2007,  11:52 Найти цитируемый пост)
шаблоны С++ сложны? 
безопасны? 

1. Мы говорим о шаблонах вообще (как о конструкции языка) или о конкретных реализациях в виде boost, stl и т.п.?
2. Возможно, что это только мне так невезло, но я видел намного больше проблем, созданных препроцессором (неумелым его использованием), чем шаблонами. Во всяком случае шаблоны - часть языка, и в большинстве случаев компилятор тут же дает по рукам при попытке неправильного их использования. С препроцессором это не так.


Автор: Любитель 25.5.2007, 10:02
Цитата(MAKCim @  19.5.2007,  16:42 Найти цитируемый пост)
в С тоже нет шаблонов  

В названии темы стоят плюсы  smile 

Цитата(nerezus @  19.5.2007,  17:29 Найти цитируемый пост)
 А мне кажестся, что на уровне синтаксиса это было бы удобнее

Угу.

Цитата(Mayk @  19.5.2007,  17:31 Найти цитируемый пост)
А вот самое интересное:

Опять-таки - гораздо лучше иметь синтаксис языковой для переменного кол-ва типов шаблонов. Если не ошибаюсь сие уже давно обсуждается комитетом.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)