I have a long list of string conditions. For low latency and code readability, I prefer using switch than "else if". Thanks to comments I edited this question and implement the switching by mapping string to callable :
#include <unordered_map>
#include <iostream>
#include <functional>
#include <thread>
struct Message{
Message(const std::string field_name, const std::string data) : m_FieldName(field_name), m_Data(data) {}
const std::string m_FieldName;
const std::string m_Data;
};
class Handler{
static const std::unordered_map<std::string, std::function<void(const Message &)>> m_FieldNameCallback;
public:
bool operator()(Message message){
bool res = true;
auto it = m_FieldNameCallback.find(message.m_FieldName);
if(it != m_FieldNameCallback.cend()){
it->second(message);
}
else{
std::cout << "Invalid message with field name: " << message.m_FieldName <<"\n";
res = false;
}
return res;
}
};
const std::unordered_map<std::string, std::function<void(const Message &)>> Handler::m_FieldNameCallback = {
{"BusinessAction", [](const Message & message){std::cout<< 5 << ": " << message.m_Data << "\n";}},
{"BusinessClass", [](const Message & message){std::cout<< 6 << ": " << message.m_Data << "\n";}},
//...
{"PriceVariation", [](const Message & message){std::cout<< 695 << ": " << message.m_Data << "\n";}},
{"PairedVolume", [](const Message & message){std::cout<< 698 << ": " << message.m_Data << "\n";}}
};
int main(){
Handler h1;
std::thread t1(h1, Message("BusinessAction", "&&&##@@@"));
std::thread t2(h1, Message("BusinessClass", "&##@"));
std::thread t3(h1, Message("Business", "&##@"));
t1.join();
t2.join();
t3.join();
}
Is Handler thread safe? using modern C++, are there any more idiomatic method for switching over string?
You definitly made good progress. Either make the map a non-static member of the handler function static. Now I think there is a strange mix. Here is some things I would do slightly different, if you have questions just let me know.
#include <unordered_map>
#include <iostream>
#include <functional>
#include <future>
struct Message
{
Message(const std::string field_name, const std::string data) : m_FieldName(field_name), m_Data(data) {}
const std::string m_FieldName;
const std::string m_Data;
};
//---------------------------------------------------------------------------------------------------------------------
class Handler final // small tweak, no inheritance support (e.g. virtual methods/destructor)
{
/*static*/ const std::unordered_map<std::string, std::function<void(const Message&)>> m_FieldNameCallback;
std::mutex m_output_mtx;
public:
Handler() :
m_FieldNameCallback
{
{"BusinessAction", [this](const Message& message) {show_message(5,message); }},
{"BusinessClass", [this](const Message& message) {show_message(6,message); }},
//...
{"PriceVariation", [this](const Message& message) {show_message(695,message); }},
{"PairedVolume", [this](const Message& message) {show_message(698,message); }}
}
{
}
bool operator()(const Message& message) // pass by const ref, message should not change and ref will avoid copy
{
// I prefer exception based error handling, so an example of that here.
// also allows us to use at() instead of find
try
{
// no lock needed since map is readonly
auto callback = m_FieldNameCallback.at(message.m_FieldName);
callback(message);
return true;
}
catch (const std::out_of_range&)
{
show_invalid_message(message);
return false;
}
}
private:
void show_invalid_message(const Message& message)
{
std::unique_lock<std::mutex> lock(m_output_mtx);
std::cout << "Invalid message with field name: " << message.m_FieldName << "\n";
}
void show_message(unsigned int number, const Message& message)
{
std::unique_lock<std::mutex> lock(m_output_mtx);
std::cout << number << ": " << message.m_Data << "\n";
}
};
int main()
{
Handler handler;
// async is a higher level abstraction then thread
// it also allows you to get values calculated on other thread wiht future.get()
// also any uncaught exceptions will be rethrown by get (allowing you to pass errors between threads)
auto ft1 = std::async(std::launch::async, [&handler] { handler(Message{ "BusinessAction", "&&&##@@@" }); });
auto ft2 = std::async(std::launch::async, [&handler] { handler(Message{ "BusinessClass", "&##@" }); });
auto ft3 = std::async(std::launch::async, [&handler] { handler(Message{ "Business", "&##@" }); });
ft1.get();
ft2.get();
ft3.get();
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.