Table des matières
Windows
Compilation
git clone https://github.com/boostorg/boost.git git checkout boost-1.69.0 --recurse-submodules # C'est celui dans le dossier boost pas boost\tools\build bootstrap.bat b2 -j4 toolset=msvc-14.0 address-model=64 architecture=x86 threading=multi --build-type=complete variant=debug,release install --prefix=boost.install
Compilation pour Visual Studio 2015 et pour des programmes en 64 bits (address-model
). architecture
vaut x86
que ce soit pour address-model
à 32 ou 64.
Il n'y a pas link
ni runtime-link
de défini. Les deux versions static
et shared
seront compilés.
On génère simultanément la version de release
et debug
.
Nommage de la dll
boost::asio::execution_context
L'exécuteur a les caractéristiques suivantes :
- Fonctionnement entre thread, pas entre application via TCP,
- Toujours en fonctionnement. En attente s'il n'a plus de travail à faire.
- cpp/boost/executor/executor.h
#pragma once #include <functional> #include <memory> class PriorityScheduler final { public: // Classe satisfaisant l'interface Executor. class ExecutorType final { public: ExecutorType(PriorityScheduler* ctx, int pri); ~ExecutorType(); ExecutorType(ExecutorType&& other) noexcept; ExecutorType(ExecutorType const& other) = delete; ExecutorType& operator=(ExecutorType&& other) noexcept = delete; ExecutorType& operator=(ExecutorType const& other) = delete; // Pour boost::asio::dispatch const PriorityScheduler& context() const noexcept; void add(std::function<void()> f); private: struct ExecutorTypeImpl; std::unique_ptr<ExecutorTypeImpl> impl_; }; PriorityScheduler(); ~PriorityScheduler(); PriorityScheduler(PriorityScheduler&& other) noexcept = delete; PriorityScheduler(PriorityScheduler const& other) = delete; PriorityScheduler& operator=(PriorityScheduler&& other) noexcept = delete; PriorityScheduler& operator=(PriorityScheduler const& other) = delete; ExecutorType get_executor(int pri) noexcept; void run(); void stop(); private: struct PrioritySchedulerImpl; std::unique_ptr<PrioritySchedulerImpl> impl_; }; bool operator==(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept; bool operator!=(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept;
- cpp/boost/executor/executor.cpp
#include "executor.h" #include <algorithm> #include <atomic> #include <boost/asio/dispatch.hpp> #include <boost/asio/execution_context.hpp> #include <chrono> #include <condition_variable> #include <mutex> #include <queue> #include <utility> #include <vector> struct PriorityScheduler::PrioritySchedulerImpl final : public boost::asio::execution_context { void run() { std::unique_lock<std::mutex> lock(mutex_); for (;;) { condition_.wait(lock, [&] { return stopped_ || !queue_.empty(); }); if (stopped_) { return; } std::shared_ptr<item_base> p(queue_.top()); queue_.pop(); lock.unlock(); p->execute_(p); lock.lock(); } } void stop() { stopped_ = true; condition_.notify_all(); } struct item_base { // Priorité de l'ordre. int priority_ = 0; // Pour trier les item ayant le même ordre. std::chrono::high_resolution_clock::time_point timestamp; // Fonction a exécuter dans un wrapper compatible avec // boost::asio::dispatch. std::function<void(std::shared_ptr<item_base>&)> execute_; }; template <class Func> struct item final : item_base { item(int pri, Func&& f) : function_(std::forward<Func>(f)) { priority_ = pri; execute_ = [](std::shared_ptr<item_base>& p) { Func tmp(std::move(static_cast<item*>(p.get())->function_)); p.reset(); tmp(); }; timestamp = std::chrono::high_resolution_clock::now(); } private: Func function_; }; // Pour comparer les items et savoir quel sera la prochaine fonction à // exécuter. struct item_comp { bool operator()(const std::shared_ptr<item_base>& a, const std::shared_ptr<item_base>& b) const { if (a->priority_ != b->priority_) { return a->priority_ < b->priority_; } return a->timestamp > b->timestamp; } }; std::mutex mutex_; std::condition_variable condition_; std::priority_queue<std::shared_ptr<item_base>, std::vector<std::shared_ptr<item_base>>, item_comp> queue_; private: std::atomic<bool> stopped_{false}; }; struct PriorityScheduler::ExecutorType::ExecutorTypeImpl { public: ExecutorTypeImpl(PriorityScheduler* ctx, int pri) noexcept : context_(ctx), priority_(pri) { } ~ExecutorTypeImpl() = default; ExecutorTypeImpl(ExecutorTypeImpl&& other) noexcept = delete; ExecutorTypeImpl(ExecutorTypeImpl const& other) = default; ExecutorTypeImpl& operator=(ExecutorTypeImpl&& other) noexcept = delete; ExecutorTypeImpl& operator=(ExecutorTypeImpl const& other) = delete; // Pour boost::asio::dispatch const PriorityScheduler& context() const noexcept { return *context_; } static void on_work_started() {} static void on_work_finished() {} // Partout Func est boost::asio::detail::work_dispatcher<void()> template <class Func, class Alloc> void dispatch(Func&& f, const Alloc& a) const { post(std::forward<Func>(f), a); } private: PriorityScheduler* context_; int priority_; template <class Func, class Alloc> void post(Func&& f, const Alloc& a) const { // On se force à utiliser l'allocateur fournit. std::shared_ptr<PriorityScheduler::PrioritySchedulerImpl::item_base> p( std::allocate_shared< PriorityScheduler::PrioritySchedulerImpl::item<Func>>( typename std::allocator_traits<Alloc>::template rebind_alloc<char>( a), priority_, std::forward<Func>(f))); // On sécurise seulement queue_. { std::lock_guard<std::mutex> lock(context_->impl_->mutex_); context_->impl_->queue_.push(p); } context_->impl_->condition_.notify_one(); } // Pour boost::asio::dispatch template <class Func, class Alloc> void defer(Func&& f, const Alloc& a) const { post(std::forward<Func>(f), a); } }; PriorityScheduler::ExecutorType::ExecutorType(PriorityScheduler* ctx, int pri) : impl_(std::make_unique<ExecutorTypeImpl>(ctx, pri)) { } PriorityScheduler::ExecutorType::~ExecutorType() = default; PriorityScheduler::ExecutorType::ExecutorType(ExecutorType&& other) noexcept = default; const PriorityScheduler& PriorityScheduler::ExecutorType::context() const noexcept { return impl_->context(); } void PriorityScheduler::ExecutorType::add(std::function<void()> f) { boost::asio::dispatch(*impl_, f, nullptr); } bool operator==(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept { return &a.context() == &b.context(); } bool operator!=(const PriorityScheduler::ExecutorType& a, const PriorityScheduler::ExecutorType& b) noexcept { return &a.context() != &b.context(); } PriorityScheduler::PriorityScheduler() : impl_(std::make_unique<PrioritySchedulerImpl>()) { } PriorityScheduler::~PriorityScheduler() = default; PriorityScheduler::ExecutorType PriorityScheduler::get_executor( int pri) noexcept { return PriorityScheduler::ExecutorType(this, pri); } void PriorityScheduler::run() { impl_->run(); } void PriorityScheduler::stop() { impl_->stop(); }
- cpp/boost/executor/main.cpp
#include <iostream> #include <thread> #include "executor.h" int main() { PriorityScheduler sched; PriorityScheduler::ExecutorType&& nulle = sched.get_executor(-1); PriorityScheduler::ExecutorType&& low = sched.get_executor(0); PriorityScheduler::ExecutorType&& med = sched.get_executor(1); PriorityScheduler::ExecutorType&& high = sched.get_executor(2); med.add([] { std::cout << "2\n"; }); low.add([] { std::cout << "1\n"; }); med.add([] { std::cout << "22\n"; }); low.add([] { std::cout << "11\n"; }); high.add([] { std::cout << "3\n"; }); high.add([] { std::cout << "33\n"; }); high.add([] { std::cout << "333\n"; }); nulle.add([&sched] { sched.stop(); }); std::thread t([&sched] { sched.run(); }); t.join(); }
boost::algorithm
boost::algorithm::join et boost::adaptors::transformed
#include <iostream> #include <boost/algorithm/string/join.hpp> #include <boost/range/adaptor/transformed.hpp> #include <string> struct Data { std::string name; std::string version; }; int main() { std::vector<Data> v{ {"Name1", "Version 1"}, {"Name2", "Version 2"} }; std::cout << boost::algorithm::join( v | boost::adaptors::transformed( [](const Data& firmware) { return firmware.name + " / " + firmware.version; } ), ", ") << std::endl; return 0; }
Migrer de boost vers std
Pointeur intelligent
Aucune différence entre :
std::shared_ptr
etboost::shared_ptr
,std::unique_ptr
etboost::unique_ptr
,std::weak_ptr
etboost::weak_ptr
,std::make_shared
etboost::make_shared
,std::enable_shared_from_this
etboost::enable_shared_from_this
.
shared_ptr
, make_shared
et enable_shared_from_this
doivent tous venir de la même libraire. L'un en version std
et l'autre en version boost
sont incompatibles.
- boost::ref et std::ref.
assign
Utiliser list_initializer.
//const std::list<int> primes = boost::assign::list_of(2)(3)(5)(7)(11); const std::list<int> primes {2, 3, 5, 7, 11};
foreach
short array_short[] = { 1, 2, 3 }; BOOST_FOREACH( short & i, array_short ) ++i;
short array_short[] = { 1, 2, 3 }; for (short & i : array_short) ++i;
Et avec des containers multi valeurs :
std::map<const int, int> m; int key, value; BOOST_FOREACH(boost::tie(key, value), m) { // do something with key and value here }
std::map<int, int> m; int key, value; // Ici, key sera en lecture seule (implicite à la structure de std::map) et value sera accessible en écriture. // En cas de présente / absence explicite de const, cela s'applique obligatoirement à toutes les variables. for(auto & [key, value] : m) { // do something with key and value here }
optional
Il ne devrait pas y avoir de problèmes. Il faut noter que std
ne supporte pas les références : std::optional<int&>
.
boost::none
devient std::nullopt
.
regex
Cette fonctionnalité était très peu utilisée.
boost::regex_search(name, whatpath, expmatchIndexPath, boost::match_default); // std::regex_search ne supporte pas le 4ème paramètre. std::regex_search(name, whatpath, expmatchIndexPath);
Sinon, boost::cmatch
et boost::regex
sont identiques à std::cmatch
et std::regex
.
variant
boost::variant<int, double> v = 5; double d = boost::get<double>(v); // Génère une exception double *d = boost::get<double>(&v); // Renvoi nullptr
devient
std::variant<int, double> v = 5; double d = std::get<double>(v); // Génère une exception double *d = std::get_if<double>(&v); // Renvoi nullptr
boost::apply_visitor
devient std::visit
.
Attention, boost::variant<int, int>
est accepté mais pas std::variant<int, int>
. Dans tous les cas, il ne faut pas y avoir deux fois le même type.
tuple
Non testé la migration.
bind
Les deux sont compatibles. Mais il est préférable de les remplacer par des fonctions lambda.
filesystem
Dans les cas basiques que j'ai eu, je n'ai pas eu de différences. Mais il y a quelques différences apparemment. Archive du 06/05/2019 le 03/03/2020
boost::filesystem::ifstream
#include <boost/filesystem/fstream.hpp> boost::filesystem::path currentPath; boost::filesystem::ifstream ifs(nextPath);
devient
#include <filesystem> #include <fstream> std::filesystem::path currentPath; std::ifstream ifs(nextPath.c_str());
boost::filesystem::copy_option
Il devient std::filesystem::copy_options
. Le nom des enum est différent :
overwrite_if_exists
devient overwrite_existing
.
fail_if_exists
devient skip_existing
.
- Deprecated
leaf()
devient filename()
.
Deprecated names and features Archive du 29/12/2014 le 21/04/2020
thread
thread.join
: si le thread n'est pasjoinable()
,boost
ne fait rien maisstd
génère une exception.
shared_mutex
Il n'y a pas d'équivalent car std
ne supporte pas le timeout.
Il faut alors faire une boucle où on passe son temps à faire un try_lock_shared
pendant le temps nécessaire.
scoped_array
Peut se remplacer sans problème par un std::vector
.
algorithm
- string
std::string str; return boost::to_upper_copy(str);
devient
std::string str; std::transform(str.begin(), str.end(), str.begin(), ::toupper); return std::move(str);
boost::lexical_cast
boost::lexical_cast<std::string>(number)
devient std::to_string(number)
.