3. C++ et le monde extérieur




3.1. Boost

La librairie boost a pour but d'améliorer la STL en fournissant un ensemble de classes et d'algorithmes annexes et sert de laboratoire expérimental avant l'intégration aux librairies C++ (plus de 100 librairies)

Certaines des fonctionnalités de boost ont été incorporées dans la version C++11, C++14

Parmi les fonctionnalités de boost, on peut citer :

Voir la documentation 1.60

Sous Ubuntu 14.04 - 64 bits compiler avec -L/usr/lib/x86_64-linux-gnu -lboost_date_time ...

3.1.1. Vérification de type et conversion

On utilise les fonctionnalités de boost/lexical_cast.hpp

  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. #include <boost/lexical_cast.hpp>
  5. using boost::lexical_cast;
  6. using boost::bad_lexical_cast;
  7.  
  8. using boost::numeric_cast;
  9. using boost::numeric::bad_numeric_cast;
  10. using boost::numeric::positive_overflow;
  11. using boost::numeric::negative_overflow;
  12.  
  13. /**
  14.  * determine type of data
  15.  */
  16. void check(string e) {
  17.     cout << "check expression : " << e << endl;
  18.     try {
  19.         int v = lexical_cast<int>(e);
  20.         cout << "- is integer" << endl;
  21.     } catch(bad_lexical_cast &) {
  22.         //
  23.     }
  24.    
  25.     try {
  26.         short int v = lexical_cast<short>(e);
  27.         cout << "- is short" << endl;
  28.     } catch(bad_lexical_cast &) {
  29.         //
  30.     }
  31.    
  32.     try {
  33.         float v = lexical_cast<float>(e);
  34.         cout << "- is float" << endl;
  35.     } catch(bad_lexical_cast &) {
  36.         //
  37.     }
  38. }
  39.  
  40.  
  41. /**
  42.  * check conversion from one type to another
  43.  */
  44. void convert() {
  45.     int v1 = -129, v2 = -3.14;
  46.    
  47.     cout << "====== CONVERT ======" << endl;
  48.    
  49.     // OK
  50.     try {
  51.         short s = numeric_cast<short>(v1);
  52.         cout << s << endl;
  53.     } catch(exception& e) {
  54.         cout << "v1 into int : " << e.what() << endl;
  55.     }
  56.    
  57.     // negative overflow
  58.     try {
  59.         signed char s = numeric_cast<signed char>(v1);
  60.         cout << s << endl;
  61.     } catch(exception& e) {
  62.         cout << "v1 into signed char : " << e.what() << endl;
  63.     }
  64.    
  65.     // OK
  66.     try {
  67.         int i = numeric_cast<int>(v2);
  68.         cout << i << endl;
  69.     } catch(exception& e) {
  70.         cout << "v2 into int : " << e.what() << endl;
  71.     }
  72.    
  73.     // negative overflow
  74.     try {
  75.         unsigned int i = numeric_cast<unsigned int>(v2);
  76.         cout << i << endl;
  77.     } catch(bad_numeric_cast& e) {
  78.         cout << "v2 into int : " << e.what() << endl;
  79.     }
  80.    
  81.    
  82. }
  83.  
  84. /**
  85.  * main function
  86.  */
  87. int main() {
  88.     // type identification
  89.     vector<string> expr = { "123456", "-1234", "abc", "-1.34" };
  90.    
  91.     for (auto e : expr) {
  92.         check(e);
  93.     }
  94.  
  95.     // type conversion
  96.     convert();
  97.        
  98.     return EXIT_SUCCESS;
  99. }
  100.  
check expression : 123456
- is integer
- is float
check expression : -1234
- is integer
- is short
- is float
check expression : abc
check expression : -1.34
- is float
====== CONVERT ======
-129
v1 into signed char : bad numeric conversion: negative overflow
-3
v2 into int : bad numeric conversion: negative overflow

3.1.2. Accumulators

Les classes liées à la librairie Accumulators permettent de faire des calculs statistiques :

  1. // g++ -o boost_accumulators.exe boost_accumulators.cpp -std=c++11 -lm
  2. // calcul du minimum, maximum, somme, moyenne, variance et
  3. // écart type d'une série de notes
  4.  
  5. #include <iostream>
  6. #include <vector>
  7. #include <algorithm>
  8. #include <cmath>
  9. using namespace std;
  10.  
  11. #include <boost/bind.hpp>
  12. #include <boost/ref.hpp>
  13. #include <boost/accumulators/accumulators.hpp>
  14. #include <boost/accumulators/statistics/stats.hpp>
  15. #include <boost/accumulators/statistics/min.hpp>
  16. #include <boost/accumulators/statistics/max.hpp>
  17. #include <boost/accumulators/statistics/sum.hpp>
  18. #include <boost/accumulators/statistics/mean.hpp>
  19. #include <boost/accumulators/statistics/variance.hpp>
  20. using namespace boost::accumulators;
  21. namespace bacc = boost::accumulators;
  22.  
  23. /**
  24.  * main function
  25.  */
  26. int main() {
  27.     vector<int> data = { 9, 10, 11, 18, 0 };
  28.    
  29.     // define an accumulator set for calculating the mean
  30.     // and variance
  31.     accumulator_set<int, stats<tag::min, tag::max, tag::sum, tag::mean, tag::variance > > acc;
  32.  
  33.     // put data in accumulator
  34.     for_each(data.begin(), data.end(), bind<void>( ref(acc), _1 ) );
  35.  
  36.  
  37.     // Display the results ...
  38.     cout << "min  = " << bacc::min(acc) << endl;
  39.     cout << "max  = " << bacc::max(acc) << endl;
  40.     cout << "sum  = " << sum(acc) << endl;
  41.     cout << "mean =   " << mean(acc) << endl;
  42.     cout << "variance = " << variance(acc) << endl;
  43.     cout << "std deviation = " << sqrt(variance(acc)) << endl;
  44.  
  45.     return 0;
  46. }
  47.  
min  = 0
max  = 18
sum  = 48
mean =   9.6
variance = 33.04
std deviation = 5.74804

3.1.3. Expressions régulières

Exemple : comment découper une chaîne de caractères en mots : la méthode n'est pas très intéressante car on trouve des chaînes vides. On découpe par rapport aux séparateurs de mots.

  1. #include <iostream>
  2. #include <string>
  3. #include <boost/regex.hpp>
  4. using namespace std;
  5.  
  6. int main() {
  7.     string s = "  all I wanna do, when I wake up in morning is see-your-eyes, Rosanna.";
  8.    
  9.     boost::regex re(",|:|-|\\.|\\s+");
  10.     boost::sregex_token_iterator it(s.begin(), s.end(), re, -1);
  11.     boost::sregex_token_iterator end;
  12.    
  13.     while (it != end) {
  14.         cout << *it++ << endl;
  15.     }
  16.    
  17.     return 0;
  18. }
  19.  
  20.  
all
I
wanna
do
   <-- chaine vide
when
I
wake
up
in
morning
is
see
your
eyes
   <-- chaine vide
Rosanna

Autre exemple avec <regex> du C++11 : on découpe par rapport aux mots, on utilise le méta-charactère \w qui représente une lettre [a-z] [A-Z] ou une lettre accentuée ou un chiffre [0-9] ou '_'.

  1. // !!!!!!!!!!!!!!!!!!!!!!
  2. // !! requires gcc 4.9 !!
  3. // !!!!!!!!!!!!!!!!!!!!!!
  4. #include <iostream>
  5. #include <regex>
  6. #include <string>
  7. #include <iterator>
  8. using namespace std;
  9.  
  10. int main() {
  11.     string s = "all I wanna do, when I wake up in morning is see-your-eyes, Rosanna";
  12.    
  13.     regex reg("[\\w]+");
  14.     sregex_iterator it(s.begin(), s.end(), reg);
  15.     sregex_iterator end;
  16.     while (it != end) {
  17.         // it gives you a smatch object
  18.         cout << (*it)[0] << endl;
  19.         ++it;
  20.     }
  21.    
  22.     return 0;
  23. }
  24.  
all
I
wanna
do
when
I
wake
up
in
morning
is
see
your
eyes
Rosanna

3.1.4. Date et heure

3.1.4.a  Exemple : nombre de jours vécus

  1. /* Short example that calculates the number of days since user was born.
  2.  * Demonstrates comparisons of durations, use of the day_clock,
  3.  * and parsing a date from a string.
  4.  */
  5. // g++ -o boost_date_time.exe boost_date_time.cpp
  6. // -lboost_date_time -L/usr/lib/x86_64-linux-gnu/
  7. #include "boost/date_time/gregorian/gregorian.hpp"
  8. using namespace boost::gregorian;
  9.  
  10. #include <iostream>
  11. using namespace std;
  12.  
  13. int main() {
  14.  
  15.   string s;
  16.   cout << "Enter birth day YYYY-MM-DD (eg: 2002-02-01): ";
  17.   cin >> s;
  18.  
  19.   try {
  20.     date birthday(from_simple_string(s));
  21.     date today = day_clock::local_day();
  22.     days days_alive = today - birthday;
  23.     days one_day(1);
  24.    
  25.     if (days_alive == one_day) {
  26.       cout << "Born yesterday, very funny" << endl;
  27.     } else if (days_alive < days(0)) {
  28.       cout << "Not born yet, hmm: " << days_alive.days()
  29.            << " days" << endl;
  30.     } else {
  31.       cout << "Days alive: " << days_alive.days() << endl;
  32.     }
  33.  
  34.   } catch(...) {
  35.     cout << "Bad date entered: " << s << std::endl;
  36.   }
  37.   return 0;
  38. }
  39.  
  40.  
> date
dimanche 21 décembre 2014, 19:08:18 (UTC+0100)
> boost_date_time.exe 
Enter birth day YYYY-MM-DD (eg: 2002-02-01): 1970-09-30
Days alive: 16153

3.1.4.b  Exemple : localisation

  1. /* The following shows the creation of a facet for the output of
  2.  * dates in French
  3.  */
  4.  
  5.   #include "boost/date_time/gregorian/gregorian.hpp"
  6.   #include <iostream>
  7.   #include <algorithm>
  8.  
  9.   /* Define a series of char arrays for short and long name strings
  10.    * to be associated with French date output (US names will be
  11.    * retrieved from the locale). */
  12.   const char* const fr_short_month_names[] =
  13.   {
  14.     "Jan", "Fev", "Mar", "Avr", "Mai", "Juin",
  15.     "Juil", "Aout", "Sep", "Oct", "Nov", "Dec", "NAM"
  16.   };
  17.   const char* const fr_long_month_names[] =
  18.   {
  19.     "Janvier", "Fevrier", "Mars", "Avril", "Mai",
  20.     "Juin", "Juillet", "Aout", "Septembre", "Octobre",
  21.     "Novembre", "Decembre", "Aucun"
  22.   };
  23.   const char* const fr_long_weekday_names[] =
  24.   {
  25.     "Dimanche", "Lundi", "Mardi", "Mercredi",
  26.     "Jeudi", "Vendredi", "Samedi"
  27.   };
  28.   const char* const fr_short_weekday_names[] =
  29.   {
  30.     "Dim", "Lun", "Mar","Mer", "Jeu", "Ven", "Sam"
  31.   };
  32.  
  33.  
  34. int main() {
  35.     using namespace boost::gregorian;
  36.    
  37.     // create some gregorian objects to output
  38.     date d1(2014, Dec, 21);
  39.     greg_month m = d1.month();
  40.     greg_weekday wd = d1.day_of_week();
  41.    
  42.     // create a facet and a locale for German dates
  43.     date_facet* french_facet = new date_facet();
  44.     std::cerr.imbue(std::locale(std::locale::classic(), french_facet));
  45.  
  46.     std::cerr << d1 << std::endl;
  47.    
  48.     // create the German name collections
  49.     date_facet::input_collection_type short_months, long_months,
  50.                                       short_weekdays, long_weekdays;
  51.     std::copy(&fr_short_month_names[0], &fr_short_month_names[11],
  52.               std::back_inserter(short_months));
  53.     std::copy(&fr_long_month_names[0], &fr_long_month_names[11],
  54.               std::back_inserter(long_months));
  55.     std::copy(&fr_short_weekday_names[0], &fr_short_weekday_names[6],
  56.               std::back_inserter(short_weekdays));
  57.     std::copy(&fr_long_weekday_names[0], &fr_long_weekday_names[6],
  58.               std::back_inserter(long_weekdays));
  59.  
  60.     // replace the default names with ours
  61.     // NOTE: date_generators and special_values were not replaced as
  62.     // they are not used in this example
  63.     french_facet->short_month_names(short_months);
  64.     french_facet->long_month_names(long_months);
  65.     french_facet->short_weekday_names(short_weekdays);
  66.     french_facet->long_weekday_names(long_weekdays);
  67.    
  68.     // output the date in French using short month names
  69.     french_facet->format("%d.%m.%Y");
  70.     std::cout << d1 << std::endl;
  71.    
  72.     french_facet->month_format("%B");
  73.     std::cout << m << std::endl;
  74.    
  75.     french_facet->weekday_format("%A");
  76.     std::cout << wd << std::endl;
  77.  
  78.  
  79.     // Output the same gregorian objects using US names
  80.     date_facet* us_facet = new date_facet();
  81.     std::cout.imbue(std::locale(std::locale::classic(), us_facet));
  82.  
  83.     us_facet->format("%m/%d/%Y");
  84.     std::cout << d1 << std::endl; //  
  85.    
  86.     // English names, iso order (year-month-day), '-' separator
  87.     us_facet->format("%Y-%b-%d");
  88.     std::cout << d1 << std::endl; //  
  89.    
  90.     return 0;
  91.  
  92.   }
  93.  
./boost_date_localization.exe 
2014-Dec-21
2014-Dec-21
Dec
Sun
12/21/2014
2014-Dec-21

3.1.5. Python

Boost offre une librairie pour interfacer Python et C++. On peut aussi utiliser Cython (cf Interopérabilité avec Python).