2009-02-10 2 views
63

Я использовал более «современные» C++-конструкции некоторое время, но вроде поверхностно и не везде. Я ищу проекты с открытым исходным кодом для изучения, которые являются хорошими примерами современного использования C++ и STL.Примеры «современного C++» в действии?

Такие вещи, как то, что предлагается в «Эффективном STL» Мейера, например, чтобы избежать циклов for и заменить их более функциональными конструкциями, используя функции boost :: bind и boost :: function и т. Д. Они по-прежнему кажутся немного неестественными для меня, и когда мне нужно что-то сделать быстро и работать, я, как правило, возвращаюсь к libc и string.h (у вас может быть мой strtok, когда вы вытаскиваете его из моих холодных, мертвых рук).

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

Можете ли вы порекомендовать несколько примеров хорошо написанных проектов с открытым исходным кодом, которые сильно используют STL и другие современные методы C++, которые я мог бы изучить? Мне особенно интересен код приложения, просмотр источников Boost был полезен, но по необходимости он очень общий, потому что это код библиотеки.

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

+1

Могу ли я забрать ваш strtok(), но дать вам strtok_r() взамен? Это поточно-безопасный и повторный. –

+0

Я отказался от strtok, когда написал класс токенизатора, который возвратил const_iterator из метода begin(), чтобы позволить мне перебирать токены. –

+3

Строка Boost Algo, Regex, Spirit, Xpressive (и даже Tokenizer, если вы несчастны) будет есть 'strok()' alive. :) – jfs

ответ

11

Здесь вы найдете несколько интересных примеров того, как подталкивания используется в проектах с открытым исходным кодом:
http://www.boost.org/users/uses_open.html

+1

Это замечательно! Я всегда пропускаю очевидные места, чтобы посмотреть .. – joeld

+1

Я бы предпочел один прекрасный пример: каждый из них использует boost и Modern C++ в разной степени и в меньшей степени, но это был лучший источник реальных примеров (а не только фрагментов) что я мог найти. – joeld

+1

Ответы, содержащие только ссылки, считаются плохой практикой (http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers). Пожалуйста, суммируйте содержание здесь (не копируйте/вставляйте), поэтому ответ может стоять сам по себе. Если вы этого не сделаете, вы рискуете удалить свой ответ, особенно если связь когда-либо умирает. –

4

Я не уверен в «хорошо написанном», но есть несколько вещей, например Hypertable и KFS, которые являются системным программным обеспечением, которое использует Boost и STL экстенсивно.

Я слышал кое-что о OpenOffice и Google Chrome, но я не смотрел их исходный код, чтобы узнать, как именно они используют STL. Я заглянул в KDE, но я бы не стал называть это современным C++. Я могу сказать вам, что какой-то код, над которым я работаю, - это много современных C++, но, увы, это не открытый исходный код, хотя я считаю, что это просто вопрос времени и терпения, чтобы получить современный C++-подход и иметь больше проектов с открытым исходным кодом принимая идиомы.

+0

Спасибо, я посмотрю на них. Это тоже было моим ощущением, что «современный» C++ широко используется в собственных проектах, но не получает гораздо более заметного «общественного» использования. – joeld

+0

Мне нравится KDE, это действительно современный C++, я думаю, используя идиому pimpl очень сильно. –

15

На самом деле, я просмотрел Google Chrome и порекомендую его. Кодировка C++ для Google guidelines - хороший эшафот для большого проекта. Они также используются и приняты в нашей команде. Более того, я очень рад, что они предоставляют свои рамки C++ mocking и testing как проекты с открытым исходным кодом. Очень удобно для крупных проектов, где вы пропускаете много приятных тестовых материалов из Java/Managed world.

+7

Я просмотрел его, отличный код, отличный пример, но не очень «Современный C++». – joeld

+6

Руководства Google по кодированию являются древними, и они не являются хорошим примером современного стиля C++. – 2012-06-03 14:29:02

+0

Исправьте ссылку на «рекомендации», пожалуйста. – nbro

23

Мейерс в порядке, однако, если вы действительно хотите, чтобы заставить себя, вы должны прочитать:

Andrei Alexandrescu - Modern C++ Design: Generic Programming and Design Patterns Applied

Это будет удар ваш разум. То, что вы узнали в книге, описывает Loki library.

Один из моих любимых ИНТ-к-типа преобразования:

template <int v> 
struct Int2Type 
{ 
    enum { value = v }; 
}; 

Я использовал его в прошлом, для моего C++ библиотеки XML сериализации для предварительного выделения вектора <> 's перед загрузкой с данными:

// We want to call reserve on STL containers that provide that function, 
// namely std::vector. 
// However, we would get a compiler error if we tried to call reserve on 
// an STL container that 
// did not provide this function. This is the solution. 
template <bool b, class T> 
class CReserve 
{ 
public: 
    static void reserve(T &lst, const int &n) 
    { reserve(lst, n, Loki::Int2Type<b>()); } 

private: 
    static void reserve(T &lst, const int &n, Loki::Int2Type<true>) 
    { lst.reserve(n); } 

    static void reserve(T &lst, const int &n, Loki::Int2Type<false>) 
    { (void)lst; (void)n; } 
}; 

Обратите внимание на частные специализации выше. Ну, если вы внимательно присмотритесь, назовем reserve(), а другой - нет. Это специализированная специализация с использованием bool как типа.

, который в свою очередь используется:

template <bool bCallReserve, class T> 
bool STLSerializeClassType(MSXML::IXMLDOMNodePtr pCurNode, T &lst, 
          CXmlArchive &archive, const char *name) 
{ 
    if(archive.IsStoring()) 
    { 
     ... 
    } else { 
     lst.clear(); 

     T::size_type nCount(0); 
     XML_ELEMENT(nCount); 

     CReserve<bCallReserve, T>::reserve(lst, nCount); 

     while(nCount--) 
     { 
      T::value_type temp; 
      temp.SerializeXml(archive, pCurNode); 
      lst.push_back(temp); 
     } 
    } 
} 

Чтобы сделать вещи простыми в C пользователей ++ кода, я добавил много определений хелперов:

#define SERIALIZE_XML_STL_CLASS(list_name, bCallReserve) \ 
(HS::STLSerializeClassType<(bCallReserve)> 
    (pCurNode, (list_name), archive, (#list_name)) 
) 

Так что в вашем коде вы хотите использовать что-то вроде:

std::list<CFred> fredList; 
SERIALIZE_XML_STL_CLASS(fredList, false); 

Или векторов:

vector<CFred> fredList; 
SERIALIZE_XML_STL_CLASS(fredList, true); 

Во всяком случае, я перестану вибрировать ... Это просто положил простой шаблон Int2Type <> для хорошего использования. Есть множество умных вещей, таких как получение компилятора для вычисления тонны материала за счет умного использования перечислений. Это действительно потрясающая книга.

+1

Почему бы не написать функцию резервного копирования шаблона, которая ничего не делает, а затем специализация для std :: vector, которая вызывает резерв? Таким образом, вызывающему абоненту не нужно передавать bool для контроля того, должен ли быть вызван резерв. Он просто показывает это на основе типа контейнера. –

+0

Да, мне нравится эта книга. Это именно тот тип вещей, который я пытаюсь применить в более широком масштабе. – joeld

+3

У меня переполнение сознания. Означает ли этот код как «писать только» после прочтения вышеупомянутой книги? – Muxecoid

5

действительно не проекты, но вот несколько отрывков:

Пример использование повышающего :: нити/повышение :: BIND:

class X { void expensive_operation(int argument); }; 

int main() 
{ 
    X x; 
    boost::thread thr(boost::bind(&X::expensive_operation, &x, 1000)); 
    std::cout << "Thread is processing..." << std::endl; 
    thr.join(); 
} 

зОго :: копировать, станд :: преобразование, BOOST_FOREACH:

int main() 
{ 
    std::vector<std::string> v; 
    std::copy(std::istream_iterator<std::string>(std::cin), 
       std::istream_iterator<std::string>(), std::back_inserter(v)); 
    BOOST_FOREACH(std::string & s, v) 
    { 
     transform(s.begin(), s.end(), s.begin(), toupper); 
    } 
    std::copy(v.begin(), v.end(), 
       std::ostream_iterator<std::string>(std::cout, " ")); 
} 

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

Наши приложения активно используют повышение :: сигналов и повышение :: функции разъединить классы, где не критичны по времени, в основном в классах интерфейса:

class ContactDetailPanel; 
class ContactListPanel { 
public: 
    void update(); 
    void edit_completed(bool change); 
    boost::function< void (Contact &) >& edit_contact();  
}; 
int main() 
{ 
    ContactListPanel clp; 
    ContactDetailPanel cdp; 

    clp.edit_contact() = boost::bind(&ContactDetailPanel::edit, &cdp, _1); 
    cdp.edit_completed() = boost::bind(&ContactListPanel::edit_completed, &clp, _1); 
    ui::signal_update().connect(boost::bind(&ContactListPanel::update, &clp));  
} 

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

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

+0

'boost :: to_upper (s)' может заменить 'transform (s.begin(), s.end(), s.begin(), toupper)'. – jfs

+0

'for_each (v.begin(), v.end(), cout << _1 <<" ");' или 'foreach (строка s, v) cout << s <<" ";' может заменить 'std :: copy (v.begin(), v.end(), std :: ostream_iterator (std :: cout, "")); ' – jfs

+0

cout << _1 <<" "- требует boost :: lambda, который Я пробовал, но не чувствую себя достаточно комфортно, чтобы написать снипп из головы. Спасибо, я не знал о boost :: to_upper (s). –

3

Adobe опубликовал много современных C++ открытым исходным кодом в последние пару лет, что, вероятно, стоит проверить:

http://opensource.adobe.com/wiki/display/site/Home

Я считаю, что их библиотека GIL либо была, либо находится в процессе добавления в Boost. их STLab содержит тонну функциональности, которая, из того, что я видел, очень чиста и очень похожа на STL-стиль.

+0

Я пытался использовать GIL около года назад и нашел его действительно потрясающим с точки зрения дизайна, но нереалистичным для работы в реальном мире. Время компиляции было плохим, его было удивительно сложно отладить, и наличие типа any_image <> было неудобным. Я слежу за ним в будущем. – joeld

2

Вот фрагмент конкатенировать вектор строк в одну строку:

vector<string> vecstr; 
vecstr.push_back("abc"); 
vecstr.push_back("efg"); // etc. 
string concat = accumulate(vecstr.begin(), vecstr.end(), string(""));