As a bit of context on the issue I have, I am trying to compile my project using MSVC (Visual Studio 2022) on Windows and it produces a bunch of errors, which is surprising, considering the same code builds just fine on GNU-G++.
What I am trying to do is to write a packet spoofer using the libtins library. I am working on a multi-threaded approach, where one thread captures the packets and pushes them to a queue and the other pops out one packet at a time, does "the spoofing", and then forwards it somewhere else.
A construct is provided for capturing network packets in a loop, in the form of a template function.
/* Credits: M.Fontanini, libtins */
template <typename Functor>
void Tins::BaseSniffer::sniff_loop(Functor function, uint32_t max_packets) {
for(iterator it = begin(); it != end(); ++it) {
try {
// If the functor returns false, we're done
#if TINS_IS_CXX11 && !defined(_MSC_VER)
if (!Tins::Internals::invoke_loop_cb(function, *it)) {
return;
}
#else
if (!function(*it->pdu())) {
return;
}
#endif
}
catch(malformed_packet&) { }
catch(pdu_not_found&) { }
if (max_packets && --max_packets == 0) {
return;
}
}
}
This works by binding a callback function which will be called every time a packet is captured. I have tried to leverage this by creating a wrapper class, called PacketSniffer, where I bind a callback function to Sniffer::sniff_loop which pushes every captured packet to a queue.
bool
PacketSniffer::callback(Tins::Packet &packet,
ThreadSafeQueue<Tins::Packet> &packetq,
bool &running) {
packetq.push(packet);
return running;
}
void PacketSniffer::run(ThreadSafeQueue<Tins::Packet> &packetq, bool &running) {
try {
sniffer_->sniff_loop(std::bind(&PacketSniffer::callback, this,
std::placeholders::_1, std::ref(packetq),
std::ref(running)));
} catch (std::exception &ex) {
throw std::runtime_error(ex.what());
}
}
The actual call where I use this in my app:
// Packet capture
bool running = true;
std::thread capture([&pq = packetq_, st, &running,
&iface_value, &pcap_filter_value]() {
PacketSniffer ps(st, iface_value.data(),
pcap_filter_value.data());
ps.run(pq, running);
});
MSVC compiler error:
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,18): error C2672: 'operator __surrogate_func': no matchi
ng overloaded function found [C:\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
C:\Users\adrian\repos\src\spoofer\src\sniffer.cpp(74): message : see reference to function template instantiation 'void Tins::BaseSniffer::sn
iff_loop<std::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,bool &),spoofer::
PacketSniffer *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>>(Functor,uint32_t)' b
eing compiled [C:\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
with
[
Functor=std::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,boo
l &),spoofer::PacketSniffer *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>
]
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,1): error C2893: Failed to specialize function template
'unknown-type std::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,bool &),spo
ofy::PacketSniffer *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>::operator ()(_Un
bound &&...) noexcept(<expr>) const' [C:\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326\include\functional(2002): message : see declaration of 'std
::_Binder<std::_Unforced,bool (__cdecl spoofer::PacketSniffer::* )(Tins::Packet &,ThreadSafeQueue<Tins::Packet> &,bool &),spoofer::PacketSniffe
r *,const std::_Ph<1> &,std::reference_wrapper<ThreadSafeQueue<Tins::Packet>>,std::reference_wrapper<bool>>::operator ()' [C:\Users\adrian\r
epos\src\spoofer\build\src\spoofer.vcxproj]
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,1): message : With the following template arguments: [C:
\Users\adrian\repos\src\spoofer\build\src\spoofer.vcxproj]
C:\Users\adrian\repos\src\spoofer\build\_deps\libtins-src\include\tins/sniffer.h(681,1): message : '_Unbound={Tins::PDU &}' [C:\Users\adrian
\repos\src\spoofer\build\src\spoofer.vcxproj]
A minimal, single threaded example from one of my tests, producing the same error. Don't know how useful this is, as it needs to be compiled and linked against libtins, but maybe it can provide some additional context:
#include <memory>
#include <iostream>
#include <exception>
#include <functional>
#include <tins/tins.h>
#include "utils/queue.h"
enum class SnifferType { Sniffer, FileSniffer };
class PacketSniffer {
public:
PacketSniffer(SnifferType st, const char *iface, const char *capture_filter) {
setup(st, iface, capture_filter);
}
PacketSniffer() = delete;
void run(ThreadSafeQueue<Tins::Packet>& packetq, bool &running);
private:
void setup(SnifferType st, const char *iface, const char *capture_filter) {
Tins::SnifferConfiguration config;
config.set_promisc_mode(true);
config.set_filter(capture_filter);
try {
if (st == SnifferType::FileSniffer) {
sniffer_ = std::make_unique<Tins::FileSniffer>(iface, config);
} else {
sniffer_ = std::make_unique<Tins::Sniffer>(iface, config);
}
} catch (Tins::pcap_error &e) {
throw std::runtime_error(e.what());
} catch (std::exception &e) {
throw std::runtime_error(e.what());
}
}
bool callback(Tins::Packet& packet,
ThreadSafeQueue<Tins::Packet>& packetq,
bool &running){
packetq.push(packet);
return running;
}
std::unique_ptr<Tins::BaseSniffer> sniffer_;
};
struct TestContext {
TestContext(const char *file_path, const char *filter) :
sniffer_({ SnifferType::FileSniffer, file_path, filter}) {}
PacketSniffer sniffer_;
ThreadSafeQueue<Tins::Packet> queue_;
};
int main() {
TestContext ctx("packets.pcap", "");
bool running = true;
ctx.sniffer_.run(ctx.queue_, running);
return 0;
}
What am I missing here regarding std::bind, that produces these errors? I find it weird that the code compiles on G++ but not on MSVC and I think it's related to this somehow.
Related
I'm doing a little file watcher in C++, but after some refactoring I got stuck with some problem. Mainly I understand what's the problem. I call a function which is actually not a function, but I cannot find such thing. All answers say that there is some name which is called as a function.
Here is my header:
#ifndef FILEWATCHER_H
#define FILEWATCHER_H
#include <unordered_map>
#include <filesystem>
namespace fs = std::filesystem;
class FileWatcher
{
size_t currentNumberOfFiles = 0;
fs::path pathToWatch;
std::unordered_map<fs::path, fs::file_time_type> pathsMap;
std::string currentTime();
public:
FileWatcher(fs::path path);
void start();
};
#endif
And the .cpp file:
#pragma warning(disable : 4996)
#include "FileWatcher.h"
#include "Event.h"
std::string FileWatcher::currentTime()
{
auto now = std::chrono::system_clock::now();
std::time_t nowTime = std::chrono::system_clock::to_time_t(now);
std::string currentSystemTime = std::ctime(&nowTime);
return currentSystemTime;
}
FileWatcher::FileWatcher(fs::path pathToWatch)
{
this->pathToWatch = pathToWatch;
//create a map with last modification of a given file in the directory
for (auto& file : fs::directory_iterator(this->pathToWatch))
{
pathsMap.emplace(file.path(), fs::last_write_time(file));
}
}
void FileWatcher::start()
{
while (true)
{
currentNumberOfFiles = std::distance(fs::directory_iterator(pathToWatch), fs::directory_iterator());
for (std::unordered_map<fs::path, fs::file_time_type>::iterator it = pathsMap.begin(); it != pathsMap.end(); )
{
if (!fs::exists(it->first))
{
if (currentNumberOfFiles < pathsMap.size())
{
//std::cout << "File was erased" << std::endl;
it = pathsMap.erase(it);
//FileType fileType = ( ? FileType::FILE : FileType::DIRECTORY);
std::string time = this->currentTime();
Event event(EventType::DELETED, FileType::FILE, it->first, time);
event.printEvent();
}
else
{
//std::cout << "Renamed" << std::endl;
it = pathsMap.erase(it);
}
}
else
{
it++;
}
}
for (auto& file : fs::directory_iterator(pathToWatch))
{
if (!pathsMap.count(file.path()))
{
//std::cout << "File has been created" << std::endl;
pathsMap.emplace(file.path(), fs::last_write_time(file));
}
else
{
if (pathsMap.at(file.path()) != fs::last_write_time(file))
{
//std::cout << "File has been modified" << std::endl;
pathsMap.at(file.path()) = fs::last_write_time(file);
}
}
}
}
}
Here is the error list:
1st error:
Severity Code Description Project File Line Column Category Source Suppression State
Error C2056 illegal expression ProgrammingAssignment C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash 130 44 Build
2nd error:
Severity Code Description Project File Line Column Category Source Suppression State
Error C2064 term does not evaluate to a function taking 1 arguments ProgrammingAssignment C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash 131 53 Build
This is the place error list refer to in the filesystem library.
template <class _Hasher, class _Kty>
_INLINE_VAR constexpr bool _Nothrow_hash = noexcept(
static_cast<size_t>(_STD declval<const _Hasher&>()(_STD declval<const _Kty&>())));
This is the error output:
Build started...
1>------ Build started: Project: ProgrammingAssignment, Configuration: Debug Win32 ------
1>FileWatcher.cpp
1>C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash(131,53): error C2064: term does not evaluate to a function taking 1 arguments
1>C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash(155): message : see reference to variable template 'const bool _Nothrow_hash<std::hash<std::filesystem::path>,std::filesystem::path>' being compiled
1>C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash(155): message : while compiling class template member function 'size_t std::_Uhash_compare<_Kty,_Hasher,_Keyeq>::operator ()<_Kty>(const _Keyty &) noexcept(<expr>) const'
1> with
1> [
1> _Kty=std::filesystem::path,
1> _Hasher=std::hash<std::filesystem::path>,
1> _Keyeq=std::equal_to<std::filesystem::path>,
1> _Keyty=std::filesystem::path
1> ]
1>C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash(1218): message : see reference to variable template 'const bool _Nothrow_hash<std::_Umap_traits<std::filesystem::path,std::chrono::time_point<std::filesystem::_File_time_clock,std::chrono::duration<__int64,std::ratio<1,10000000> > >,std::_Uhash_compare<std::filesystem::path,std::hash<std::filesystem::path>,std::equal_to<std::filesystem::path> >,std::allocator<std::pair<std::filesystem::path const ,std::chrono::time_point<std::filesystem::_File_time_clock,std::chrono::duration<__int64,std::ratio<1,10000000> > > > >,0>,std::filesystem::path>' being compiled
1>C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash(1218): message : while compiling class template member function 'std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>> std::_Hash<std::_Umap_traits<_Kty,std::chrono::time_point<std::filesystem::_File_time_clock,std::chrono::duration<std::chrono::system_clock::rep,std::chrono::system_clock::period>>,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>::erase<std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>>,0>(std::_List_iterator<std::_List_val<std::_List_simple_types<_Ty>>>) noexcept(<expr>)'
1> with
1> [
1> _Ty=std::pair<const std::filesystem::path,std::filesystem::file_time_type>,
1> _Kty=std::filesystem::path,
1> _Hasher=std::hash<std::filesystem::path>,
1> _Keyeq=std::equal_to<std::filesystem::path>,
1> _Alloc=std::allocator<std::pair<const std::filesystem::path,std::filesystem::file_time_type>>
1> ]
1>C:\VisualStudio2019\VC\Tools\MSVC\14.28.29910\include\xhash(130,44): error C2056: illegal expression
1>Done building project "ProgrammingAssignment.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The error messages are very difficult to read, but it basically boils down to a missing implementation of std::hash<std::filesystem::path>.
std::unordered_map uses hashes to order its elements. By default, it uses a specialization of std::hash on the map's key_type. However, the standard library does not provide a specialization of std::hash for std::filesystem::path, hence the errors.
So, if you want to use std::filesystem::path as the key_type of std::unordered_map, you have to either:
provide your own specialization of std::hash<std::filesystem::path>, eg:
template <>
class std::hash<fs::path>
{
public:
size_t operator()(const fs::path &path) const
{
return ... a hash of path ...;
}
};
class FileWatcher
{
...
std::unordered_map<fs::path, fs::file_time_type> pathsMap;
...
};
implement a custom class/struct with an operator() that takes a std::filesystem::path as input and returns a unique value as output. Then you can explicitly state that type in the std::unordered_map's Hash template parameter, eg:
struct MyPathHash
{
size_t operator()(const fs::path &path) const
{
return ... a hash of path ...;
}
};
class FileWatcher
{
...
std::unordered_map<fs::path, fs::file_time_type, MyPathHash> pathsMap;
...
};
Otherwise, use std::map instead. It uses operator< to order its elements, and std::filesytem::path has its own operator< implemented, eg:
...
#include <map>
class FileWatcher
{
...
std::map<fs::path, fs::file_time_type> pathsMap;
...
};
I was following a talk on YouTube by Kelvin Henney based on the idiom of Functional C++... About 50 minutes into the video he starts showing an example class structure that he named channel. Then he writes the simple fizzbuzz function and is going to pass that into a server like piece of code using threads. I'm using the code from his video which can be found here: Kevlin Henney - Functional C++
However, when I try to compile the program, Visual Studio is generating the C2661 compiler error pointing to std::tuple... which is coming from the std::tread's constructor within my code.
main.cpp
#include <iostream>
#include <exception>
#include <string>
#include <thread>
#include "server.h"
std::string fizzbuzz(int n) {
return
n % 15 == 0 ? "FizzBuzz" :
n % 3 == 0 ? "Fizz" :
n % 5 == 0 ? "Buzz" :
std::to_string(n);
}
void fizzbuzzer(channel<int> & in, channel<std::string> & out) {
for (;;)
{
int n;
in.receive(n);
out.send(fizzbuzz(n));
}
}
int main() {
try {
channel<int> out;
channel<std::string> back;
std::thread fizzbuzzing(fizzbuzzer, out, back);
for (int n = 1; n <= 100; ++n) {
out << n;
std::string result;
back >> result;
std::cout << result << "\n";
}
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
server.h
#pragma once
#include <condition_variable>
#include <queue>
#include <mutex>
#include <iostream>
template<typename ValueType>
class receiving;
template<typename ValueType>
class channel {
private:
std::mutex key;
std::condition_variable_any non_empty;
std::queue<ValueType> fifo;
public:
void send(const ValueType & to_send) {
std::lock_guard<std::mutex> guard(key);
fifo.push(to_send);
non_empty.notify_all();
}
bool try_receive(ValueType & to_receive) {
bool received = false;
if (key.try_lock()) {
std::lock_guard<std::mutex> guard(key, std::adopt_lock);
if (!fifo.empty()) {
to_receive = fifo.front();
fifo.pop();
received = true;
}
}
return received;
}
void receive(ValueType & to_receive) {
std::lock_guard<std::mutex> guard(key);
non_empty.wait(
key,
[this] {
return !fifo.empty();
});
to_receive = fifo.front();
fifo.pop();
}
void operator<<(const ValueType & to_send) {
send(to_send);
}
receiving<ValueType> operator>>(ValueType & to_receive) {
return receiving(this, to_receive);
}
};
template<typename ValueType>
class receiving {
private:
channel<ValueType> * that;
ValueType & to_receive;
public:
receiving(channel<ValueType> * that, ValueType & to_receive)
: that(that), to_receive(to_receive)
{}
receiving(receiving && other)
: that(other.that), to_receive(other.to_receive)
{
other.that = nullptr;
}
operator bool() {
auto from = that;
that = nullptr;
return from && from->try_recieve(to_receive);
}
~receiving() {
if (that)
that->receive(to_receive);
}
};
I know that the code he is showing is only an example code, but I figured I would try it within my IDE while following the video to get a better understanding of his talk. I'd like to be able to compile this just to see the generated output, and to be able to step through the debugger and disassembler, but I've hit a roadblock at this point. I understand the generated compiler error, just not sure how to resolve it based on his code sample...
Here's the compiler error that is being generated:
1>------ Build started: Project: Computations, Configuration: Debug Win32 ------
1>main.cpp
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(2539): error C2661: 'std::tuple<void (__cdecl *)(channel<int> &,channel<std::string> &),channel<int>,channel<std::string>>::tuple': no overloaded function takes 3 arguments
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\thread(46): note: see reference to function template instantiation 'std::unique_ptr<std::tuple<void (__cdecl *)(channel<int> &,channel<std::string> &),channel<int>,channel<std::string>>,std::default_delete<_Ty>> std::make_unique<std::tuple<void (__cdecl *)(channel<int> &,channel<std::string> &),channel<int>,channel<std::string>>,void(__cdecl &)(channel<int> &,channel<std::string> &),channel<int>&,channel<std::string>&,0>(void (__cdecl &)(channel<int> &,channel<std::string> &),channel<int> &,channel<std::string> &)' being compiled
1> with
1> [
1> _Ty=std::tuple<void (__cdecl *)(channel<int> &,channel<std::string> &),channel<int>,channel<std::string>>
1> ]
1>c:\users\skilz99\source\repos\computations\computations\main.cpp(31): note: see reference to function template instantiation 'std::thread::thread<void(__cdecl &)(channel<int> &,channel<std::string> &),channel<int>&,channel<std::string>&,void>(_Fn,channel<int> &,channel<std::string> &)' being compiled
1> with
1> [
1> _Fn=void (__cdecl &)(channel<int> &,channel<std::string> &)
1> ]
1>Done building project "Computations.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
I think I have misunderstood how function pointers work. In this example:
class Helper
{
public:
typedef void (*SIMPLECALLBK)(const char*);
Helper(){};
void NotifyHelperbk(SIMPLECALLBK pCbk)
{ m_pSimpleCbk = pSbk; }
private:
SIMPLECALLBK m_pSimpleCbk;
}
// where i call the func
class Main
{
public:
Main(){};
private:
Helper helper
void SessionHelper(const char* msg);
}
Main.cpp
void Main::SessionHelper(const char* msg)
{
....
}
helper.NotifyHelperbk(&Main::SessionHelper);
I get the following error:
error C2664: 'Main::NotifyHelperbk' : cannot convert parameter 1 from 'void (__thiscall Main::* )(const char *)' to 'Helper::SIMPLECALLBK'
1> There is no context in which this conversion is possible
What am I missing here?
Main::SessionHelper is a non static method. So add static to it to be able to use it as function pointer. Or use member method pointer (you will need a instance to call it).
if you use c++11 you can use std::bind
class Helper
{
public:
void NotifyHelperbk(std::function<void(char*)> func){
/* Do your stuff */
func("your char* here");
}
And your main :
Main.cpp
Main m;
helper.NotifyHelperbk(std::bind(&Main::SessionHelper, m, std::placeholder_1));
I'm trying to use a boost::lockfree queue to manage tasks. These tasks retrieve data and would be processed on a worker thread. Once data is retrieved, a signal should be sent to the main thread with the data. The worker thread is spawned at the start of the application and just keeps polling the queue. I'm new to Boost::Asio but from my research, it seems to be the best mechanism for sending signals between threads.
I've looked at several examples, in particular:
Confused when boost::asio::io_service run method blocks/unblocks
boost asio post not working , io_service::run exits right after post
Here is my code:
#include "stdafx.h"
#include <thread>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/optional.hpp>
#include <boost/thread.hpp>
#include <boost/signals2.hpp>
typedef boost::signals2::signal<void(int)> signal_type;
class Task
{
public:
Task(int handle) : _handle(handle) {};
~Task() {};
virtual void Execute()
{
int result = _handle * 2;
}
private:
int _handle;
};
class Manager
{
public:
Manager()
{
_mainService = std::make_shared<boost::asio::io_service>();
_workerService = std::make_shared<boost::asio::io_service>();
_work = std::make_shared<boost::asio::io_service::work>(*_workerService);
_threadStarted = false;
Start();
};
~Manager() {};
void WorkerMain()
{
_workerService->poll();
}
void Start()
{
if (_threadStarted) return;
_workerThread = std::thread(&Manager::WorkerMain, this);
_threadStarted = true;
}
void Stop()
{
if (_threadStarted == false) return;
_mainService->stop();
_workerThread.join();
_mainService.reset();
}
void OnSignalFetchCompleted(int value)
{
int asdf = 0; //do stuff with data on main thread
}
void ProcessData(signal_type& signal)
{
int i = 0;
do
{
_queue.consume_one([&](std::shared_ptr<Task> task)
{
task->Execute();
//get data from task; send out signal with data
});
i++;
} while (i < 3);
}
void QueueData(int handle)
{
_signalFetchCompleted.connect(boost::bind(&Manager::OnSignalFetchCompleted, this, _1));
_workerService->post(boost::bind(&Manager::ProcessData, boost::ref(_signalFetchCompleted))); //!!does not compile
std::shared_ptr<Task> task = std::make_shared<Task>(handle);
_queue.push(task);
}
private:
boost::lockfree::spsc_queue<std::shared_ptr<Task>, boost::lockfree::capacity<1024>> _queue;
std::thread _workerThread;
bool _threadStarted;
std::shared_ptr<boost::asio::io_service> _mainService;
std::shared_ptr<boost::asio::io_service> _workerService;
std::shared_ptr<boost::asio::io_service::work> _work;
signal_type _signalFetchCompleted;
};
int _tmain(int argc, _TCHAR* argv[])
{
std::shared_ptr<Manager> mgr = std::make_shared<Manager>();
mgr->QueueData(5);
mgr->QueueData(10);
mgr->Stop();
return 0;
}
I'm getting a compile error on the _workerService->Post line that I haven't been able to resolve:
1>C:\Boost\boost/bind/mem_fn.hpp(333): error C2784: 'T *boost::get_pointer(const boost::scoped_ptr<T> &)' : could not deduce template argument for 'const boost::scoped_ptr<T> &' from 'const signal_type'
1> C:\Boost\boost/smart_ptr/scoped_ptr.hpp(150) : see declaration of 'boost::get_pointer'
1> C:\Boost\boost/bind/mem_fn.hpp(352) : see reference to function template instantiation 'R (__cdecl &boost::_mfi::dm<R,Manager>::call<const U>(U &,const void *) const)' being compiled
1> with
1> [
1> R=void (signal_type &)
1> , U=signal_type
1> ]
1> C:\Boost\boost/bind/mem_fn.hpp(352) : see reference to function template instantiation 'R (__cdecl &boost::_mfi::dm<R,Manager>::call<const U>(U &,const void *) const)' being compiled
1> with
1> [
1> R=void (signal_type &)
1> , U=signal_type
1> ]
1> C:\Boost\boost/bind/bind.hpp(243) : see reference to function template instantiation 'R (__cdecl &boost::_mfi::dm<R,Manager>::operator ()<T>(const U &) const)' being compiled
1> with
1> [
1> R=void (signal_type &)
1> , T=signal_type
1> , U=signal_type
1> ]
Any help resolving this compile error or general comments on this approach would be greatly appreciated. Thanks.
In light of new information, the problem is with your boost::bind. You are trying to call a member function without an object to call it on: you are trying to call ProcessData but you haven't told the bind on which object you wish to call it on. You need to give it a Manager to call it on:
_workerService->post(boost::bind(&Manager::ProcessData, this, boost::ref(_signalFetchCompleted)));
This will call ProcessData on this and pass in a reference to _signalFetchCompleted
The compiler error seems to be talking about you constructing a boost::asio::io_service::work object and that you are passing it incorrect parameters:
error C2664: 'boost::asio::io_service::work::work(const boost::asio::io_service::work &)' : cannot convert argument 1 from 'std::shared_ptr<boost::asio::io_service>' to 'boost::asio::io_service &'
boost::asio::io_service::work has a constructor which takes a boost::asio::io_service& and a copy constructor; however, you are passing it a std::shared_ptr<boost::asio::io_service>:
_work = std::make_shared<boost::asio::io_service::work>(_workerService);
Here, _workerService is a std::shared_ptr<boost::asio::io_service>, but you need a boost::asio::io_service&. Try the following instead:
_work = std::make_shared<boost::asio::io_service::work>(*_workerService);
I think that boost::asio is not the best solution for your task. Have you read about conditional variables? They are much more simple and can be used to achieve your goal.
I'm using the C++11 system_error error code library to create a custom error class for a library I'm making. I've done this before with boost::error_code, but I can't quite it get it working with std::error_code. I'm using GCC 4.6.
Basically, I've laid out all the boilerplate code to create an error class, an error_category, and the conversion routines in the STD namespace to convert my custom enums into an std::error_code object:
namespace mylib
{
namespace errc {
enum my_error
{
failed = 0
};
inline const char* error_message(int c)
{
static const char* err_msg[] =
{
"Failed",
};
assert(c < sizeof(err_msg) / sizeof(err_msg[0]));
return err_msg[c];
}
class my_error_category : public std::error_category
{
public:
my_error_category()
{ }
std::string message(int c) const
{
return error_message(c);
}
const char* name() const { return "My Error Category"; }
const static error_category& get()
{
const static my_error_category category_const;
return category_const;
}
};
} // end namespace errc
} // end namespace mylib
namespace std {
inline error_code make_error_code(mylib::errc::my_error e)
{
return error_code(static_cast<int>(e), mylib::errc::my_error_category::get());
}
template<>
struct is_error_code_enum<mylib::errc::my_error>
: std::true_type
{ };
The problem is, implicit conversion between my error code enums and std::error_code objects doesn't seem to be working, so I can't for example try and compare an instance of std::error_code with enum literals:
int main()
{
std::error_code ec1 = std::make_error_code(mylib::errc::failed); // works
std::error_code ec2 = mylib::errc::failed; // doesn't compile
bool result = (ec2 == mylib::errc::failed); // doesn't compile
}
The expression ec2 == mylib::errc::failed won't compile - I have to say ec2 == std::make_error_code(mylib::errc::failed).
The error the compiler emits is:
In file included from test6.cc:3:0:
/usr/include/c++/4.6/system_error: In constructor ‘std::error_code::error_code(_ErrorCodeEnum, typename std::enable_if<std::is_error_code_enum<_ErrorCodeEnum>::value>::type*) [with _ErrorCodeEnum = mylib::errc::my_error, typename std::enable_if<std::is_error_code_enum<_ErrorCodeEnum>::value>::type = void]’:
test6.cc:70:37: instantiated from here
/usr/include/c++/4.6/system_error:127:9: error: cannot convert ‘mylib::errc::my_error’ to ‘std::errc’ for argument ‘1’ to ‘std::error_code std::make_error_code(std::errc)’
And here's an Ideone link.
So, why isn't this working? Do I need additional boilerplate code to enable mylib::errc::my_error enums to be implicitly convertible to std::error_code? I thought that the specialization of std::make_error_code takes care of that?
You have to move error_code make_error_code(mylib::errc::my_error e) function from std to your error namespace (mylib::errc). Please check http://ideone.com/eSfee.