Отправляет email-рассылки с помощью сервиса Sendsay

RSS-канал «C++ User Journal - Ukraine»

Доступ к архиву новостей RSS-канала возможен только после подписки.

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

   

Подписаться на другой RSS-канал, зная только его адрес или адрес сайта.

Код формы подписки на этот канал для вашего сайта:

Форма для любого другого канала

Последние новости

Конечный автомат
2007-04-10 18:57 jetsnail
Конечный автомат и его генерация средствами Си++ компилятора на основе шаблонов, без полиморфизма. Рекомендую всем.

P.S.: Статья дает краткое описание идеи реализации конечного автомата на шаблонах. Есть простой пример на Си++, на основе которого, приложившись, можно сделать довольно сложную и в то же время очень удобную машину состояний.

Сведи компилятор с ума!
2007-04-06 21:25 jetsnail
Сегодня вечером нечего было делать, вот я и решил свести свой компилятор с ума. Я думаю, что каждый из вас работал со списками типов, но никто не делал вот так:

struct A {
};

template<typename TList>
struct MultipleInheritance :
  public TList::Head,
  public MultipleInheritance<typename TList::Tail>
{
};

template <typename T1>
struct RecTList {
  typedef T1 Head;
  typedef RecTList< RecTList<T1> > Tail;
};

typedef RecTList<A> ARecTList;

class RectClass : public MultipleInheritance<ARecTList> {};

int main() {
  return 0;
}

gcc долго-долго думает, потом корректно обрабатывает эту ситуацию, если NN значение параметра -ftemplate-depth-NN не слишком большое, но если, к примеру, его увеличить, то получим  нехватку памяти (памяти у меня много, так что ждать я не стал, кому интересно - попробуйте свалить gcc в core, поделитесь результатами).

А вот Microsoft Visual Studio 2005 SP1 просто сходит с ума:

1>------ Build started: Project: crec, Configuration: Debug Win32 ------
1>Compiling...
1>main.cpp
1>x:\temp\crec\main.cpp(6) : fatal error C1001: An internal error has occurred in the compiler.
1>(compiler file 'msc1.cpp', line 1393)
1> To work around this problem, try simplifying or changing the program near the locations listed above.
1>Please choose the Technical Support command on the Visual C++
1> Help menu, or open the Technical Support help file for more information
1>        x:\temp\crec\main.cpp(9) : see reference to class template instantiation 'MultipleInheritance<TList>' being compiled
1>        x:\temp\crec\main.cpp(9) : see reference to class template instantiation 'MultipleInheritance<RecTList<T1>>' being compiled
1>Build log was saved at "file://x:\Temp\crec\Debug\BuildLog.htm"
1>crec - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Будьте осторожнее.

Как подружиться с шаблонными параметрами
2006-04-13 20:41 jetsnail

Мэтью Уилсон (Matthew Wilson) в своей статье “Дружественные Шаблоны” (Friendly Templates) которую вы можете найти в оригинале по адресу http://www.cuj.com/documents/s=8943/cujexp0312wilson2/ рассказал о том, как использовать шаблонные параметры в объявлении друзей классов. Его статья послужила толчком для некоторых интересных C++ решений. Ниже представлен перевод статьи Мэтью (немного лишней информации я убрал, однако важная информация от начала и до конца представлена в полном объеме) и мои исправления/дополнения.

Статья Мэтью Уилсона.

Иногда возникают ситуации, когда необходимо объявить друга класса, однако его тип представлен в виде шаблонного параметра. Например:

// Пример #1
template <typename T>
class Thing
{
  friend T; // Разрешает классу T доступ ко всем данным и методам данного класса.

private:
  int value_;
};

Выглядит вполне разумно, не так ли? Но это не стандартный C++. В стандарте языка C++ (документ C++-98 Standard (ISO/IEC 14882)), пункт 7.1.5.3(2) сказано, что внутри шаблонного класса с параметром типа T конструкция вида “friend class T;” запрещена (http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1520.pdf).

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

Пример #1, приведенный выше, обрабатывается такими компиляторами как: Borland (5.51 and 5.6), Comeau (4.3.0.1), Digital Mars (GCC (2.95), Intel (6 and 7), Watcom (11 and 12), and Visual C++ (4.2 through 7.1). Однако он не работает с CodeWarrior (7 and 8) или GCC (3.2). С компилятором Comeau код работает в стандартной конфигурации, если же указать флаг “—strict”, то компилятор начнет “ругаться”, что конструкция и все ее возможные формы не являются стандартными.

Шаблонный параметр, по сути, может быть простым типом (POD type), а не классом, например типом “int”. Для некоторых компиляторов - это проблема. Такие типы не могут быть друзьями, поэтому стоит указать, что тип, переданный в качестве шаблонного параметра – это класс. Например:

// Пример #2
template <typename T>
class Thing
{
  friend class T; // Разрешает классу T доступ ко всем данным и методам данного класса.

private:
  int value_;
};

Этот пример работает без проблем с CodeWarrior, Digital Mars и Watcom компиляторами. Таким образом первый либо второй пример нам подходит в том или ином случае. Однако проблемы до сих пор остаются для компилятора GCC версии 3.2.

Будучи тем, кто сторонится использования “друзей”, я не смог придумать решение этой проблемы и проконсультировался с ребятами из группы comp.lang.c++.moderated (http://www.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&newwindow=1&threadm=5d33192c.0310010048.44c06c13@posting.google.com&rnum=1&prev=), которые посоветовали два следующих примера:

// Пример #3
template <typename T>
class Thing
{
  struct friend_maker
  {
    typedef T T2;
  };

  typedef typename friend_maker::T2 friend_type;
  friend class friend_type;

private:
  int value_;
};

// Пример #4
template <typename T>
class Thing
{
  template<class T2>
  struct friend_maker
  {
    typedef T2 T3;
  };

  typedef typename friend_maker<T>::T3 friend_type;
  friend class friend_type;

private:
  int value_;
};

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

// Пример #5
#if defined(__BORLANDC__) || \
    defined(__COMO__) || \
    defined(__DMC__) || \
    (   defined(__GNUC__) && \
        __GNUC__ < 3) || \
    defined(__INTEL_COMPILER) || \
    defined(__WATCOMC__) || \
    defined(_MSC_VER)
# define    DECLARE_TEMPLATE_PARAM_AS_FRIEND(T)     friend T
#elif defined(__MWERKS__)
# define    DECLARE_TEMPLATE_PARAM_AS_FRIEND(T)     friend class T
#elif defined(__GNUC__) && \
      __GNUC__ >= 3
# define    DECLARE_TEMPLATE_PARAM_AS_FRIEND(T)     \
    struct friend_maker                             \
    {                                               \
        typedef T T2;                               \
    };                                              \
    typedef typename friend_maker::T2 friend_type;  \
    friend friend_type
#else
// Мы не знаем, какой компилятор используется,
// возможно следует сгенерировать ошибку, однако будем надеяться,
// что он поддерживает такую конструкцию:
# define    DECLARE_TEMPLATE_PARAM_AS_FRIEND(T)     friend T
#endif

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

// Пример #6
template <typename T>
class Thing
{
  DECLARE_TEMPLATE_PARAM_AS_FRIEND(T);

private:
  int value_;
};

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

Мои исправления и дополнения

Что произойдет, если нам будет необходимо объявить больше одного “друга”? Например вот так:

// Пример #7
template <typename T1, typename T2>
class Thing
{
  DECLARE_TEMPLATE_PARAM_AS_FRIEND(T1);
  DECLARE_TEMPLATE_PARAM_AS_FRIEND(T2);

private:
  int value_;
};

Макрос “DECLARE_TEMPLATE_PARAM_AS_FRIEND” локально объявляет структуру “friend_maker”. В данном случае она будет сгенерирована два раза, но имена отличаться не будут, что приведет к ошибке.

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

// Пример #8
# define    DECLARE_TEMPLATE_PARAM_AS_FRIEND(T)           \
  struct make_friend_##T                                  \
  {                                                       \
    typedef T T2;                                         \
  };                                                      \
  typedef typename make_friend_##T::T2 friend_type_##T;   \
  friend friend_type_##T

Вот и все, теперь можно использовать это решение в своих проектах.
Например, я сделал версию макроса для проекта Boost.

#ifndef BOOST_TEMPLATE_FRIEND_HPP
#define BOOST_TEMPLATE_FRIEND_HPP

#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>

#if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, >= 1020)
# pragma once
#endif

#if (defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3)) || \
    defined(__BORLANDC__) ||                              \
    defined(__COMO__) ||                                  \
    defined(__DMC__) ||                                   \
    defined(__WATCOMC__) ||                               \
    defined(BOOST_MSVC)  ||                               \
    defined(BOOST_INTEL)
# define BOOST_DECLARE_TEMPLATE_FRIEND(T) friend T
#elif defined(__MWERKS__)
# define BOOST_DECLARE_TEMPLATE_FRIEND(T) friend class T
#elif defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, >= 3)
# define BOOST_DECLARE_TEMPLATE_FRIEND(T)                 \
  struct make_friend_##T                                  \
  {                                                       \
    typedef T T2;                                         \
  };                                                      \
  typedef typename make_friend_##T::T2 friend_type_##T;   \
  friend friend_type_##T
#else
# define BOOST_DECLARE_TEMPLATE_FRIEND(T) friend T
#endif

#endif  // BOOST_TEMPLATE_FRIEND_HPP</div>

Добро пожаловать!
2006-04-13 00:02 jetsnail
Добрый день, уважаемые друзья. Рад приветствовать Вас в сообществе C++ разработчиков. Это сообщество создано для тех, кто заинтересован в интересных и качественных решениях проблем с помощью языка C++.

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

Я искренне надеюсь на Вашу помощь. Приглашаю к сотрудничеству заинтересованных профессионалов своего дела. Если у Вас есть знания и опыт, которыми Вы хотите поделиться с миром, помочь новичкам и, быть может, усовершенствовать свои решения с помощью профессиональной и объективной критики – добро пожаловать. Как известно, начинать всегда очень сложно, я попытаюсь сделать все от меня зависящее, чтобы качество информации было на высоте, чем собственно и хочу привлечь внимание профессионалов и интересующихся. Уверен, что этот журна C++ программистов будет полезен сообществу. Так же я буду переводить статьи с английского языка. Я понимаю, что английский язык очень важен и маловероятно то, что профессиональный разработчик его не знает, но все же родной язык воспринимается человеком легче и быстрее.

Если у Вас есть какие-то вопросы, замечания или предложения – пишите мне, с удовольствием отвечу каждому.

С уважением,
    Владислав Лазаренко.