I'm using boots's property_tree library. I'm looking for a way to get a child node from a ptree object, but return an empty ptree if failed. I came across a nice example in property_tree/examples/empty_ptree_trick.cpp:
void process_settings(const std::string &filename)
{
ptree pt;
read_info(filename, pt);
const ptree &settings = pt.get_child("settings", empty_ptree<ptree>());
std::cout << "\n Processing " << filename << std::endl;
std::cout << " Setting 1 is " << settings.get("setting1", 0) << std::endl;
std::cout << " Setting 2 is " << settings.get("setting2", 0.0) << std::endl;
std::cout << " Setting 3 is " << settings.get("setting3", "default") << std::endl;
}
which does exactly what I need. The problem is that the compiler complains that empty_ptree() function is not a member of boost:property_tree. Any ideas where empty_ptree() is?
I'm using boost 1.44 on VS2010.
I have just blown a full day trying to answer that question!
This was my solution. Firstly I used pointers, and not references as you have to initialize them immediately. Then I just caught the exception and added a new ptree.
using namespace boost::property_tree;
ptree r_pt;
ptree *c_pt;
read_xml( "file.xml" , r_pt);
try {
c_pt = &(r_pt.get_child( "example" ));
}
catch (ptree_bad_path) {
c_pt = &(r_pt.put_child( "example", ptree() ));
}
std::cout << "Setting 1 is " << c_pt.get("setting1", 0) << std::endl;
From what I could pick up they expect us to use the boost::optional type. But I'm just a beginner..
EDIT
I just found the implementation of empty_ptree<>.
template<class Ptree>
inline const Ptree &empty_ptree()
{
static Ptree pt;
return pt;
}
I think you can just add this to your code and use it as described in the empty_ptree_trick.cpp, but I am sticking with my solution for now untill I find out how its actually supposed to be done.
void process_settings(const std::string &filename)
{
ptree pt;
read_info(filename, pt);
const ptree &settings = pt.get_child("settings", ptree());
std::cout << "\n Processing " << filename << std::endl;
std::cout << " Setting 1 is " << settings.get("setting1", 0) << std::endl;
std::cout << " Setting 2 is " << settings.get("setting2", 0.0) << std::endl;
std::cout << " Setting 3 is " << settings.get("setting3", "default") << std::endl;
}
Note, that will prevent throwing an instance of 'boost::wrapexceptboost::property_tree::ptree_bad_path'
Related
i want to make container of futures ,each future is void result of a task so that i could use wait_for_any on the container ,each task is coroutine which i currently implement using yield_context,and inside this coroutine there initiating function which returns ec and result where i use ec to analyze result.and then another coroutine is called passes same yield_context .
i want to know how to make this design.
and if i ll use use_future ,how can i pass error code to ec not throwing it unless there is no way except throwing it ,in this case i ll put try and catch around async initiating functions.
all these tasks will be posted ,spawned ... on asio io_service .
this is my main parts of code:
this is the spawn of task
boost::asio::spawn(GetServiceReference(), boost::bind(&HTTPRequest::Execute, boost::placeholders::_1, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map()));
and this is the coroutine using yield_context
void HTTPRequest::Execute(boost::asio::yield_context yield_r, std::string request_name, std::map<std::string, boost::shared_ptr<HTTPResponse>>& mHTTPClient_Responses_Map)
{
resolver_iterator iterator_connect = boost::asio::async_connect(mSock, iterator_resolve, yield_r[ec]);
}
and inside Execute we use ec to analyze
if (ec == boost::system::errc::errc_t::success){}
and here we start another coroutine passing same yield_context
SendRequest(yield_r);
}
i want to change this so i have container of futures for all spawned Execute,i do not care about results of Execute because i put them to member class Response.
But i need result in future so that i can use wait_any on the container .
If you can change your implementation, use the async_result pattern.
This makes it so you can use your method with any of the approaches (completion handler, yield context or use_future).
I reproduce the self-contained example from here for inspiration:
Comprehensive Demo
Showing how to use it with with
coro's and yield[ec]
coro's and yield + exceptions
std::future
completion handlers
Live On Coliru
#define BOOST_COROUTINES_NO_DEPRECATION_WARNING
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp>
using boost::system::error_code;
namespace asio = boost::asio;
template <typename Token>
auto async_meaning_of_life(bool success, Token&& token)
{
#if BOOST_VERSION >= 106600
using result_type = typename asio::async_result<std::decay_t<Token>, void(error_code, int)>;
typename result_type::completion_handler_type handler(std::forward<Token>(token));
result_type result(handler);
#else
typename asio::handler_type<Token, void(error_code, int)>::type
handler(std::forward<Token>(token));
asio::async_result<decltype (handler)> result (handler);
#endif
if (success)
handler(error_code{}, 42);
else
handler(asio::error::operation_aborted, 0);
return result.get ();
}
void using_yield_ec(asio::yield_context yield) {
for (bool success : { true, false }) {
boost::system::error_code ec;
auto answer = async_meaning_of_life(success, yield[ec]);
std::cout << __FUNCTION__ << ": Result: " << ec.message() << "\n";
std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
}
}
void using_yield_catch(asio::yield_context yield) {
for (bool success : { true, false })
try {
auto answer = async_meaning_of_life(success, yield);
std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
} catch(boost::system::system_error const& e) {
std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
}
}
void using_future() {
for (bool success : { true, false })
try {
auto answer = async_meaning_of_life(success, asio::use_future);
std::cout << __FUNCTION__ << ": Answer: " << answer.get() << "\n";
} catch(boost::system::system_error const& e) {
std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
}
}
void using_handler() {
for (bool success : { true, false })
async_meaning_of_life(success, [](error_code ec, int answer) {
std::cout << "using_handler: Result: " << ec.message() << "\n";
std::cout << "using_handler: Answer: " << answer << "\n";
});
}
int main() {
asio::io_service svc;
spawn(svc, using_yield_ec);
spawn(svc, using_yield_catch);
std::thread work([] {
using_future();
using_handler();
});
svc.run();
work.join();
}
Prints:
using_yield_ec: Result: Success
using_yield_ec: Answer: 42
using_yield_ec: Result: Operation canceled
using_yield_ec: Answer: 0
using_future: Answer: 42
using_yield_catch: Answer: 42
using_yield_catch: Caught: Operation canceled
using_future: Caught: Operation canceled
using_handler: Result: Success
using_handler: Answer: 42
using_handler: Result: Operation canceled
using_handler: Answer: 0
Note: for simplicity I have not added output synchronization, so the output can become intermingled depending on runtime execution order
There are many similar questions on here already but unfortunately, none has solved my problem so far.
I am stuck connecting Qt to a simple sqlite database. The connection can be established, but queries fail with No query Unable to fetch row and db.tables() returns me no tables.
My code is the following:
void DBManager::connOpen()
{
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setDatabaseName(m_db_path);
m_db.open();
if (!m_db.open())
{
qDebug("Error: Connection to database failed.");
}
else
{
qDebug("Connection to database established.");
QSqlQuery query(m_db);
query.prepare("SELECT * FROM data1");
if (!query.exec())
{
std::cout << query.lastError().text().toStdString() << std::endl;
std::cout << query.executedQuery().toStdString() << std::endl;
}
while (query.next())
{
std::cout << query.value("id").toString().toStdString() << ". " << query.value("one").toString().toStdString() << std::endl;
}
QSqlDriver *driver = m_db.driver();
QStringList tables = m_db.tables();
std::cout << "tables found: " << tables.count() << std::endl;
for(QString table: tables)
{
QSqlRecord record = driver->record(table);
std::cout << "name: " << table.toStdString() << std::endl;
std::cout << "count: " << record.count() << std::endl;
std::cout << record.fieldName(0).toStdString() << std::endl;
}
}
}
This leads to console output like this:
Connection to database established.
No query Unable to fetch row
SELECT * FROM data1
tables found: 0
My database should have one table (data1). Executing the query by hand returns this:
Any help is appreciated, thank you.
It came down to a very stupid mistake.
I was using a sqlite2 database that I created using sqlite mydb while QSQLITE is the driver for sqlite3 (using sqlite3 mydb).
I am writing simple chat in Qt + Apache Thrift but right now I need to face a problem with connecting multiple clients. On first sight everything looks good and I cannot find where the problem is.
Here is my server main.cpp:
int main(int argc, char **argv)
{
int port = 9090;
::apache::thrift::stdcxx::shared_ptr<UsersStorageHandler> handler(new UsersStorageHandler());
::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new UsersStorageProcessor(handler));
::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
std::cout << "Users server started..." << std::endl;
std::cout << std::endl;
std::cout << std::endl;
server.serve();
return 0;
}
Here is my server handler.h:
class UsersStorageHandler : virtual public UsersStorageIf
{
public:
UsersStorageHandler();
int32_t subscribeUser(const std::string& username);
void unsubscribeUser(const int32_t userID);
private:
Users users;
};
Here is my server handler.cpp:
UsersStorageHandler::UsersStorageHandler()
{
srand(time(NULL));
}
int32_t UsersStorageHandler::subscribeUser(const std::string &username)
{
++idGenerator;
assert(username != "");
User user;
user.userId = idGenerator;
user.username = username;
user.colorR = (rand() % 255) + 0;
user.colorG = (rand() % 255) + 0;
user.colorB = (rand() % 255) + 0;
user.colorA = 0;
users[idGenerator] = user;
std::cout << "NEW USER CONNECTED" << std::endl;
std::cout << "==================" << std::endl;
std::cout << "Username:\t" << user.username << std::endl;
std::cout << "User ID:\t" << user.userId << std::endl;
std::cout << "User R:\t" << user.colorR << std::endl;
std::cout << "User G:\t" << user.colorG << std::endl;
std::cout << "User B:\t" << user.colorB << std::endl;
std::cout << "User A:\t" << user.colorA << std::endl;
std::cout << "==================" << std::endl;
std::cout << "CURRENT USERS COUNT:\t" << users.size() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
/*
* SEND TO CLIENT INFO ABOUT NEW USER HERE
*/
return idGenerator;
}
void UsersStorageHandler::unsubscribeUser(const int32_t userID)
{
auto index = users.find(userID);
assert(index != users.end());
users.erase(index);
std::cout << "USER DISCONNECTED" << std::endl;
std::cout << "=================" << std::endl;
std::cout << "USER WITH ID " << userID << " ERASED" << std::endl;
std::cout << "USERS COUNT:\t" << users.size() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
/*
* SEND TO CLIENT INFO ABOUT NEW USER HERE
*/
}
And right here is a method for connect to the server in client app:
void MainWindow::connectToServers(const std::string &ip, const uint32_t &port, const std::string &nick)
{
m_usersServerIP = ip;
m_usersServerPort = port;
try
{
::apache::thrift::stdcxx::shared_ptr<TTransport> socket(new TSocket(m_usersServerIP, m_usersServerPort));
::apache::thrift::stdcxx::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
::apache::thrift::stdcxx::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
m_usersServerClient = std::make_shared<UsersStorageClient>(protocol);
transport->open();
m_clientID = m_usersServerClient.get()->subscribeUser(nick);
QMessageBox::information(this, "Connected",
"You are connected "
"with users server");
createAndRegisterUsersServerReactor();
activateChatScreen();
}
catch (const std::exception &e)
{
qDebug() << e.what();
}
qDebug() << "ID FROM SERVER:\t" << m_clientID;
}
As far as I checked right now it is working like this:
Created two instances of client app. In one instance fill nickname, ip, port and clicked connect (connectToServers method). Client connected. In another instance done the same but after clicked connected ... nothing happens. App freezes at this line:
m_clientID = m_usersServerClient.get()->subscribeUser(nick);
After closing first client, second one connects to the server.
A TSimplerServer supports a single connection. You should try using TThreadedServer to support multiple simultaneous clients.
As Chris mentioned above either make a Threaded server to server multiple requests simultaneously. For me I have created a non-blocking server as below to be able to serve multiple clients in async manner for loose coupling.
public static void start(dataClass configData, String env, int port) throws TTransportException {
TNonblockingServerTransport transport = new TNonblockingServerSocket(port);
TNonblockingServer.Args nBlockServer = new TNonblockingServer.Args(transport);
ccmProviderServiceImpl impl = new ccmProviderServiceImpl(configData, env);
Processor<ccmProviderServiceImpl> processor = new ccmProviderService.Processor<>(impl);
TServer server = new TNonblockingServer(nBlockServer.processor(processor));
//custom event handling for tracking
ccmServerEventHandler cse = new ccmServerEventHandler();
server.setServerEventHandler(cse);
server.serve();
}
I am trying yaml-cpp (r589:2c954b1ed301), but I have a trouble with following code.
#include <iostream>
#include <yaml-cpp/yaml.h>
int main()
{
YAML::Node doc;
std::cout << doc << std::endl; // SEGV
doc["sub"] = YAML::Node();
std::cout << doc << std::endl; // OK
doc = YAML::Load("");
std::cout << doc << std::endl; // OK
std::cout << YAML::Load("") << std::endl; // SEGV
std::cout << YAML::Load("a") << std::endl; // OK
YAML::Node doc2 = YAML::Load("");
std::cout << doc2 << std::endl; // SEGV
return 0;
}
The code is compiled with g++ 4.4.7 on Scientific Linux 6.4.
I am not sure that this error occurs only on my environment.
I would appreciate your comments and suggestions.
This was a bug, but it was fixed (see the bug report).
I have a class (contains a few scalar values and a vector of floats) and I want to read and write an instance as the value of another map.
// write
out << YAML::Key << "my_queue" << YAML::Value << my_queue;
// read (other code cut out...)
for (YAML::Iterator it=doc.begin();it!=doc.end();++it)
{
std::string key, value;
it.first() >> key;
it.second() >> value;
if (key.compare("my_queue") == 0) {
*it >> my_queue;
}
}
Writing this class works perfectly, but I can't seem to read it no matter what I do. It keeps throwing an InvalidScalar.
Caught YAML::InvalidScalar yaml-cpp: error at line 20, column 13: invalid scalar
and this is that the output (written with yaml-cpp without it reporting any errors) looks like:
Other Number: 80
my_queue:
size: 20
data:
- 3.5
- -1
- -1.5
- 0.25
- -24.75
- -5.75
- 2.75
- -33.55
- 7.25
- -11
- 15
- 37.5
- -3.75
- -28.25
- 18.5
- 14.25
- -36.5
- 6.75
- -0.75
- 14
max_size: 20
mean: -0.0355586
stdev: 34.8981
even_more_data: 1277150400
The documentation seems to say this is supported usage, a nested map, in this case with a sequence as one of the values. It complains about it being an InvalidScalar, even though the first thing I do it tell it that this is a map:
YAML::Emitter& operator << ( YAML::Emitter& out, const MeanStd& w )
{
out << YAML::BeginMap;
out << YAML::Key << "size";
out << YAML::Value << w.size();
out << YAML::Key << "data";
out << YAML::Value << YAML::BeginSeq;
for(Noor::Number i=0; i<w.size(); ++i) {
out << w[i];
}
out << YAML::EndSeq;
out << YAML::Key << "max_size";
out << YAML::Value << w.get_max_size();
out << YAML::Key << "mean";
out << YAML::Value << w.mean();
out << YAML::Key << "stdev";
out << YAML::Value << w.stdev();
out << YAML::EndMap;
return out;
}
Does anyone see a problem with this?
When you're reading the YAML:
std::string key, value;
it.first() >> key;
it.second() >> value; // ***
if (key.compare("my_queue") == 0) {
*it >> my_queue;
}
The marked line tries to read the value of the key/value pair as a scalar (std::string); that's why it tells you that it's an invalid scalar. Instead, you want:
std::string key, value;
it.first() >> key;
if (key.compare("my_queue") == 0) {
it.second() >> my_queue;
} else {
// ...
// for example: it.second() >> value;
}
YAML::Node internalconfig_yaml = YAML::LoadFile(configFileName);
const YAML::Node &node = internalconfig_yaml["config"];
for(const auto& it : node )
{
std::cout << "\nnested Key: " << it.first.as<std::string>() << "\n";
if (it.second.Type() == YAML::NodeType::Scalar)
{
std::cout << "\nnested value: " << std::to_string(it.second.as<int>()) << "\n";
}
if (it.second.Type() == YAML::NodeType::Sequence)
{
std::vector<std::string> temp_vect;
const YAML::Node &nestd_node2 = it.second;
for(const auto& it2 : nestd_node2)
{
if (*it2)
{
std::cout << "\nnested sequence value: " << it2.as<std::string>() << "\n";
temp_vect.push_back(it2.as<std::string>());
}
}
std::ostringstream oss;
std::copy(temp_vect.begin(), temp_vect.end(),
std::ostream_iterator<std::string>(oss, ","));
std::cout << "\nnested sequence as string: " <<oss.str() << "\n";
}
}
if (it2.second.Type() == YAML::NodeType::Map)
{
// Iterate Recursively again !!
}