Модераторы: LSD

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Delphi - приемущества и недостатки, принимаются различные высказывания 
:(
    Опции темы
Alexeis
Дата 23.1.2007, 01:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 14
Всего: 459



Цитата(Daevaorn @  22.1.2007,  23:07 Найти цитируемый пост)
Но шаблоны намного гибче. А копи-паст, хоть и встроенный, никогда до их функциональности не дойдет.

  Препроцессор морально устаревшая технология обработки кода. Шаблоны по сути это и есть препроцессор. Плата за гибкость меньшая надежность и ухудшение читабельности. Я, например, в своих программах отказываюсь от #define и заменяю его const для констант, а макросы инлайнами. Небольшая потеря гибкости в пользу прозрачности кода оправдана. Я бы все же сказал, что это сомнительное приемущество. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Daevaorn
Дата 23.1.2007, 01:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 5
Всего: 70



Цитата(Alexeis @  23.1.2007,  02:10 Найти цитируемый пост)
Шаблоны по сути это и есть препроцессор

нет. это совсем не препроцессор. те возможности которые есть у шаблонов в С++ невозможно реализовать препроцессором
PM MAIL WWW   Вверх
Alexeis
Дата 23.1.2007, 01:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 14
Всего: 459



Цитата(Daevaorn @  23.1.2007,  01:13 Найти цитируемый пост)
нет. это совсем не препроцессор

  Ведь главная его функция в подстановке реального типа вместо условного и компиляция полученного С++ кода. Так без специального указания мы получим отдельную реализацию для типов char, word, long, ULONG, и т.д. Механизм довольно схожий. Например, какие у него есть особенные возможности в части наследования, кроме той же подстановки. 
  Думаю стоит поведать о неочевидных особенностях шаблонов, иначе не видно в чем их прогрессивность в отличие от препроцессора.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Daevaorn
Дата 23.1.2007, 01:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 5
Всего: 70



Не знаю на самом деле твой уровень зания С++ и шаблонов в частности, но твои высказывания удручают.
Цитата(Alexeis @  23.1.2007,  02:25 Найти цитируемый пост)
Ведь главная его функция в подстановке реального типа вместо условного и компиляция полученного С++ кода.

Шаблоны это не только типы, но и значения.
Цитата(Alexeis @  23.1.2007,  02:25 Найти цитируемый пост)
Думаю стоит поведать о неочевидных особенностях шаблонов, иначе не видно в чем их прогрессивность в отличие от препроцессора

Думаю стоит поизучать С++, прежде чем сравнивать что-то в нем с препроцессором.
PM MAIL WWW   Вверх
SergeCpp
Дата 23.1.2007, 03:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


 
**


Профиль
Группа: Участник
Сообщений: 955
Регистрация: 8.8.2005
Где: At Home

Репутация: 3
Всего: 124



Template Meta-Programming — Wiki Pedia
Template Meta-Programming — Wiki Books

Код
// prime number computation by Erwin Unruh

template <int p, int i>
class is_prime {
public:
   enum { prim = (p==2) || (p%i) && is_prime<(i>2?p:0),i-1>::prim
        }; 
}; 

template<>
class is_prime<0,0> {
public:
   enum {prim=1};
}; 

template<>
class is_prime<0,1> {
 public:
   enum {prim=1};
}; 

template <int i>
class D {
public:
   D(void*);
}; 

template <int i>
class Prime_print {      // primary template for loop to print prime numbers
public:
   Prime_print<i-1> a; 
   enum { prim = is_prime<i,i-1>::prim
        }; 
   void f() {
       D<i> d = prim ? 1 : 0;
       a.f();
   } 
}; 

template<>
class Prime_print<1> {   // full specialization to end the loop
  public:
    enum {prim=0}; 
    void f() {
        D<1> d = prim ? 1 : 0;
    }; 
}; 

#ifndef LAST 
#define LAST 18 
#endif 

int main()
{
   Prime_print<LAST> a; 
   a.f(); 
}


PM MAIL WWW ICQ   Вверх
skyboy
Дата 23.1.2007, 03:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 1
Всего: 260



Цитата(Daevaorn @  23.1.2007,  00:35 Найти цитируемый пост)
Думаю стоит поизучать С++, прежде чем сравнивать что-то в нем с препроцессором. 

поясни, пожалуйста, малознакомым с шаблонами, почему шаблоны не могут быть реализованы через препроцессор(я не имею в виду конкретный препроцессор встроенный в конкретный компилятор, а транфсормер исходного кода вообще)?
PM MAIL   Вверх
SergeCpp
Дата 23.1.2007, 03:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


 
**


Профиль
Группа: Участник
Сообщений: 955
Регистрация: 8.8.2005
Где: At Home

Репутация: 3
Всего: 124



Макросы

Цитата
В C++ макросы не нужны! До боли знакомое высказывание, не так ли? Я бы его немного уточнил: не нужны, если вы не хотите существенно облегчить себе жизнь. 
Я полностью согласен с тем, что чрезмерное и необдуманное использование макросов может вызвать большие неприятности, особенно при повторном использовании кода. Вместе с тем, я не знаю ни одного средства C++, которое могло бы принести пользу при чрезмерном и необдуманном его использовании. 

Итак, когда макросы могут принести пользу? 

Макрос как надъязыковое средство. Хороший примером является простой, но удивительно полезный отладочный макрос _VAL_, выводящий имя и значение переменной: 
#define _VAL_(var) #var "=" << var << " "
Надъязыковой частью здесь является работа с переменной как с текстом, путем перевода имени переменной (оно существует только в исходном коде программы) в строковый литерал, реально существующий в коде бинарном. Данную возможность могут предоставить только макросы. 

Информация о текущем исходном файле и строке -- ее пользу при отладке трудно переоценить. Для этого я использую специальный макрос _ADD_. Например: 
    cout<<_ADD_("Ошибка чтения");
выведет что-то вроде 
Ошибка чтения <file.cpp:34>
А если нужен перевод строки, то стоит попробовать 
    cout<<"Ошибка чтения" _ADD_("") "\n";
Такой метод работает, потому что макрос _ADD_ возвращает строковый литерал. Вроде бы эквивалентная функция 
    char* _ADD_(char*);
вполне подошла бы для первого примера, но не для второго. Конечно, для вывода в cout это не имеет никакого значения, но в следующем пункте я покажу принципиальную важность подобного поведения. 
Рассмотрим устройство _ADD_: 

#define _ADD_tmp_tmp_(str,arg) str " <" __FILE__ ":" #arg ">"
#define _ADD_tmp_(str,arg) _ADD_tmp_tmp_(str,arg)
#define _ADD_(str) _ADD_tmp_(str,__LINE__)
Почему все так сложно? Дело в том, что __LINE__ в отличие от __FILE__ является числовым, а не строковым литералом и чтобы привести его к нужному типу придется проявить некоторую смекалку. Мы, конечно, не можем написать: 
#define _ADD_(str) str " <" __FILE__ ":" #__LINE__ ">"
т.к. # может быть применен только к аргументу макроса. Решением является передача __LINE__ в виде параметра некоторому вспомогательному макросу, но очевидное 
#define _ADD_tmp_(str,arg) str " <" __FILE__ ":" #arg ">"
#define _ADD_(str) _ADD_tmp_(str,__LINE__)
не работает: результатом _ADD_("Ошибка чтения") будет 
"Ошибка чтения <file.cpp:__LINE__>"
что нетрудно было предвидеть. В итоге мы приходим к приведенному выше варианту, который обрабатывается препроцессором следующим образом: _ADD_("Ошибка чтения") последовательно подставляется в 
_ADD_tmp_("Ошибка чтения",__LINE__)
_ADD_tmp_tmp_("Ошибка чтения",34)
"Ошибка чтения" " <" "file.cpp" ":" "34" ">"
"Ошибка чтения <file.cpp:34>"

Получение значения числового макроса в виде строки. Как показывает практика, данная возможность находит себе применение и за пределами подробностей реализации "многоэтажных" макросов. Допустим, что для взаимодействия с SQL-сервером у нас определен класс DB::Query с соответствующей функцией 
void DB::Query::Statement(const char *);
и мы хотим выбрать все строки некоторой таблицы, имеющие равное некому "магическому числу" поле somefield: 
#define FieldOK 7
// ...
DB::Int tmp(FieldOK);
q.Statement(" SELECT * "
            " FROM sometable "
            " WHERE somefield=? "
);
q.SetParam(), tmp;
Излишне многословно. Как бы это нам использовать FieldOK напрямую? Недостаточно знакомые с возможностями макросов программисты делают это так: 
#define FieldOK 7
// ...
#define FieldOK_CHAR "7"
// ...
q.Statement(" SELECT * "
            " FROM sometable "
            " WHERE somefield=" FieldOK_CHAR
);
В результате чего вы получаете все прелести синхронизации изменений взаимосвязанных наборов макросов со всеми вытекающими из этого ошибками. Правильным решением будет 
#define FieldOK 7
// ...
q.Statement(" SELECT * "
            " FROM sometable "
            " WHERE somefield=" _GETSTR_(FieldOK)
);
где _GETSTR_ определен следующим образом: 
#define _GETSTR_(arg) #arg
Кстати, приведенный пример наглядно демонстрирует невозможность полностью эквивалентной замены всех числовых макросов на принятые в C++ 
const int FieldOK=7;
enum { FieldOK=7 };
макрос _GETSTR_ не сможет с ними работать. 

Многократно встречающиеся части кода. Рассмотрим еще один пример из области работы с SQL-сервером. Предположим, что нам нужно выбрать данные из некоторой таблицы. Это можно сделать в лоб: 
struct Table1 {  // представление данных таблицы
       DB::Date  Field1;
       DB::Int   Field2;
       DB::Short Field3;
};

void f()
{
 Table1 tbl;
 DB::Query q;
 q.Statement(" SELECT Field1, Field2, Field3 "
             " FROM Table1 "
 );
 q.BindCol(), tbl.Field1, tbl.Field2, tbl.Field3;
 // ...
}
И этот метод действительно работает. Но что, если представление таблицы изменилось? Теперь нам придется искать и исправлять все подобные места -- чрезвычайно утомительный процесс! Об этом стоило позаботиться заранее: 
#define TABLE1_FLD      Field1, Field2, Field3
#define TABLE1_FLD_CHAR "Field1, Field2, Field3"

struct Table1 {  // представление данных таблицы
       DB::Date  Field1;
       DB::Int   Field2;
       DB::Short Field3;

       // вспомогательная функция
       void BindCol(DB::Query& q) { q.BindCol(), TABLE1_FLD; }
};

void f()
{
 Table1 tbl;
 DB::Query q;
 q.Statement(" SELECT " TABLE1_FLD_CHAR
             " FROM Table1 "
 );
 tbl.BindCol(q);
 // ...
}
Теперь изменение структуры таблицы обойдется без зубовного скрежета. Стоит отметить, что в определении TABLE1_FLD_CHAR я не мог использовать очевидное _GETSTR_(TABLE1_FLD), т.к. TABLE1_FLD содержит запятые. К сожалению, данное печальное ограничение в примитивном препроцессоре C++ никак нельзя обойти. 

Многократно встречающиеся подобные части кода. Представим себе, что мы пишем приложение для банковской сферы и должны выбрать информацию по некоторым счетам. В России, например, счет состоит из многих полей, которые для удобства работы собирают в специальную структуру, а в таблице он может быть представлен смежными полями с одинаковым префиксом: 
q.Statement(" SELECT Field1, AccA_bal, AccA_cur, AccA_key, AccA_brn, "
            " AccA_per, Field2 "
            " FROM Table1 "
);
q.BindCol(), tbl.Field1, tbl.AccA.bal, tbl.AccA.cur, tbl.AccA.key,
             tbl.AccA.brn, tbl.AccA.per, tbl.Field2;
// ...
Можете себе представить, сколько писанины требуется для выбора четырех счетов (tbl.AccA, tbl.AccB, tbl.KorA, tbl.KorB). И снова на помощь приходят макросы: 
#define _SACC_(arg) #arg"_bal, "#arg"_cur, "#arg"_key, "#arg"_brn, " \
                    #arg"_per "
#define _BACC_(arg) arg.bal, arg.cur, arg.key, arg.brn, arg.per

// ...

q.Statement(" SELECT Field1, " _SACC_(AccA) " , Field2 "
            " FROM Table1 "
);
q.BindCol(), tbl.Field1, _BACC_(tbl.AccA), tbl.Field2;
// ...
Думаю, что комментарии излишни. 

Рассмотрим более тонкий пример подобия. Пусть нам потребовалось создать таблицу для хранения часто используемой нами структуры данных: 
struct A {
       MyDate Date;
       int    Field2;
       short  Field3;
};
Мы не можем использовать идентификатор Date для имени столбца таблицы, т.к. DATE является зарезервированным словом SQL. Эта проблема легко обходится с помощью приписывания некоторого префикса: 
struct TableA {
       DB::Date  xDate;
       DB::Int   xField2;
       DB::Short xField3;

       TableA& operator=(A&);
       void Clear();
};
А теперь определим функции-члены: 
TableA& TableA::operator=(A& a)
{
 xDate=ToDB(a.Date);
 xField2=ToDB(a.Field2);
 xField3=ToDB(a.Field3);

 return *this;
}

void TableA::Clear()
{
 xDate="";
 xField2="";
 xField3="";
}
Гарантирую, что если TableA содержит хотя бы пару-тройку десятков полей, то написание подобного кода вам очень быстро наскучит, мягко говоря! Нельзя ли это сделать один раз, а потом использовать результаты? Оказывается можно: 
TableA& TableA::operator=(A& a)
{
// используем склейку лексем: ##
#define ASS(arg) x##arg=ToDB(a.arg);
 ASS(Date);
 ASS(Field2);
 ASS(Field3);
#undef ASS

 return *this;
}

void TableA::Clear()
{
#define CLR(arg) x##arg=""
 CLR(Date);
 CLR(Field2);
 CLR(Field3);
#undef CLR
}
Теперь определение TableA::Clear()по TableA::operator=() не несет никакой нудной работы, если, конечно, ваш текстовый редактор поддерживает команды поиска и замены. Так же просто можно определить и обратное присваивание: A& A::operator=(TableA&). 
Надеюсь, что после приведенных выше примеров вы по-новому посмотрите на роль макросов в C++.


Сергей Деревяго. C++ 3rd: комментарии

PM MAIL WWW ICQ   Вверх
SergeCpp
Дата 23.1.2007, 04:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


 
**


Профиль
Группа: Участник
Сообщений: 955
Регистрация: 8.8.2005
Где: At Home

Репутация: 3
Всего: 124



Трансформер исходного кода [шаблонов] вообще == компилятор языка программирования C++

Цитата
Templates are different from macros. A macro, which is also a compile-time language feature, generates code in-line using text manipulation and substitution. Macro systems often have limited compile-time process flow abilities and usually lack awareness of the semantics and type system of their companion language (an exception should be made with Lisp's macros, which are written in Lisp itself).

Template Meta-Programming

Обращаю внимание рассматривающих английский текст на то, что под "макросами" понимаются именно макросы "вообще"

PM MAIL WWW ICQ   Вверх
Daevaorn
Дата 23.1.2007, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 5
Всего: 70



Цитата(skyboy @  23.1.2007,  04:41 Найти цитируемый пост)
поясни, пожалуйста, малознакомым с шаблонами, почему шаблоны не могут быть реализованы через препроцессор(я не имею в виду конкретный препроцессор встроенный в конкретный компилятор, а транфсормер исходного кода вообще)? 

Начем с того что препроцессинг кода произходит на первой стадии его обработки, ещё до компиляции.  И препроцессор ничего не знает о типа, да и о языке программирования практически тоже. 
Такие полезные возможности как частичная/полная специализыция, вывод типов, expression templates не могут быть реализованы до процесса компиляции никаким препроцессором. Поэтому все кто сравнивают механизм шаблонов в С++ с препроцессором, просто не знают С++ и являются заложниками слова "шаблон".
PM MAIL WWW   Вверх
Alexeis
Дата 23.1.2007, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 14
Всего: 459



SergeCpp, тем не мене в простейшем виде, например
Код

            template<class T>
            class stack {
               T* v;
               T* p;
               int sz;
            public:
               stack(int s) { v = p = new T[sz=s]; }
               ~stack() { delete[] v; }
               void push(T a) { *p++ = a; }
               T pop() { return *--p; }
               int size() const { return p-v; }
            };

Разница между макросом и шаблоном совершенно не видна.

Цитата

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


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

А теперь посмотрите как реализуется метод шаблонного класса вне описания шаблона
Код

    template<class T> void stack<T>::push(T a)
            {
               *p++ = a;
            }
    template<class T> stack<T>::stack(int s)
            {
               v = p = new T[sz=s];
            }

Простым и удобным такой синтаксис трудно назвать..


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Beltar
Дата 23.1.2007, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 627
Регистрация: 11.1.2006

Репутация: 2
Всего: 7



Цитата

А ведь если переформулировать этот тезис как: «стоит создавать языки с возможно более простой грамматикой», он уже не кажется таким смешным, нет


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

Цитата

В C++ макросы не нужны! До боли знакомое высказывание, не так ли? Я бы его немного уточнил: не нужны, если вы не хотите существенно облегчить себе жизнь.


С этим ИМХО в Майкрософт.

Цитата

Разница между макросом и шаблоном совершенно не видна.


А также между описанной мной фичей.
Хотелось бы увидеть более сложный пример, причем по возможности типовой, а не уникальный, нужный раз в год.

Цитата

Написание шаблона тебует большого внимания и контроля над кодом.


На С пишут одни супермены, так что им это как два байта переслать. smile

PS Самое гибкое это набор кода руками.

PPS А вот что обязательно нужно ввести и в Си и в Паскаль (не помню название Паскаль-компилятора в котором это сделали, работает он под VS) так это case\switch со строками. smile


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. smile(с) я, хотя может и нет
Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере.
PM MAIL   Вверх
skyboy
Дата 26.1.2007, 01:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 1
Всего: 260



ёлки-моталки, только-только узнал, что в Делфи есть пространство имён  smile 
Точнее, что можно обращаться к идентификаторам, объявленным в разных модулях по имени модуля   smile 
PM MAIL   Вверх
pythonwin
Дата 26.1.2007, 09:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 2529
Регистрация: 18.4.2006
Где: за компом

Репутация: 1
Всего: 36



Цитата(skyboy @  26.1.2007,  04:13 Найти цитируемый пост)
ёлки-моталки, только-только узнал, что в Делфи есть пространство имён  smile 
Точнее, что можно обращаться к идентификаторам, объявленным в разных модулях по имени модуля   smile  

кстати, во время преподавания Delphi мне это запрещали smile
почему? не понятно...
PM WWW GTalk Jabber   Вверх
nerezus
Дата 26.1.2007, 09:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: 13
Всего: 43



Цитата

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


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
Beltar
Дата 26.1.2007, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 627
Регистрация: 11.1.2006

Репутация: 2
Всего: 7



Цитата

в Делфи есть пространство имён 


Это не пространство имен, размазанное по куче файлов, а нормальное разделение видимости по юнитам. И было оно со времен появления в Паскале раздельной компиляции, в учебниках все это есть.

Цитата

"В бассейн Дельфин требуется инструктор по плаванию, умеющий плавать"


Да-да. И вообще Delphi'ны тупые и т. д. и т. п. Delphi не виноват, что его преподают в вузах и куча студентов, которым на него наплевать, лишь бы зачет был, заваливает интеренет-конферренции глупостями. А преподы, они вообще к новому невосприимчивы.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. smile(с) я, хотя может и нет
Пищущий на C++ мужик. Даже если это мужик сидит в написанном на Delphi и жрущем паскалевскую библиотеку билдере.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила ведения Религиозных войн
Smartov
1. Уважайте собеседника
2. Собеседник != враг
3. Старайтесь воздерживаться от тем вида "Windows Rulez" или "Linux Rulez"

С уважением, Smartov.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Религиозные войны | Следующая тема »


 




[ Время генерации скрипта: 0.0965 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.