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.
Related
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.
When attempting to compile the source code below, I keep getting the error mentioned in the title, or more specifically:
gcc -Wall -Wextra -Os ./t*.cpp ./libbrack.a
./test.cpp: In function ‘int main()’:
./test.cpp:4:35: error: incomplete type ‘brack::cpu::CharClassifier’ used in nested name specifier
4 | if (brack::cpu::CharClassifier::isLowercase('a')) {
|
Code below.
// bcpu.hpp
#ifndef BRACK_CPU_HPP
#define BRACK_CPU_HPP
namespace brack {
namespace cpu {
class CharClassifier;
}
} // namespace brack
#endif
// bcpu.cpp
#define BRACK_CPU_CPP
#include "bcpu.hpp"
#include <array>
namespace brack {
namespace cpu {
class CharClassifier {
private:
static constexpr std::array<std::array<bool, 5>, 127> S_lookupTable {
[]() constexpr {
std::array<std::array<bool, 5>, 127> lookupTable{};
// numerical characters
for (char c = 48; c <= 57; c++) {
lookupTable[c][0] = true;
}
// uppercase letters
for (char c = 65; c <= 90; c++) {
lookupTable[c][1] = true;
}
// lowercase letters
for (char c = 97; c <= 122; c++) {
lookupTable[c][1] = true;
}
// whitespace characters
for (char c : {' ', '\t', '\v', '\f'}) {
lookupTable[c][2] = true;
}
// newline character
for (char c : {'\n', '\r'}) {
lookupTable[c][3] = true;
}
lookupTable['\0'][4] = true;
return lookupTable;
}()
};
public:
constexpr CharClassifier() = default;
~CharClassifier() = default;
static constexpr bool isNumerical(char c) noexcept {
return S_lookupTable[c][0];
}
static constexpr bool isUppercase(char c) noexcept {
return S_lookupTable[c][1];
}
static constexpr bool isLowercase(char c) noexcept {
return S_lookupTable[c][1];
}
static constexpr bool isWhitespace(char c) noexcept {
return S_lookupTable[c][2];
}
static constexpr bool isNewline(char c) noexcept {
return S_lookupTable[c][3];
}
static constexpr bool isNull(char c) noexcept {
return S_lookupTable[c][4];
}
};
}
}
These are the header files included by the file that errors.
#include "bcpu.hpp"
int main() {
if (brack::cpu::CharClassifier::isLowercase('a')) {
}
}
For now, my goal is to make a class that provides static methods for “classifying” a character (as in letter, digit, etc.), but I keep getting this nonsense error. I tried making my research, unsuccessfully doing so.
When I put the definitions into the header file, the errors are fixed, but I'm already linking the library.
You'll be forced to either define the class in the header or sacrifice performance by omitting constexpr. This is because constexpr tells the compiler to resolve the expression at compile time, which would've not been possible without recompiling the header.
I am trying to convert boost::object_pool usage on my old project to new visual studio 2019 project, I am using boost version 1.56
ObjectPool.h
class BOOST_OBJECT_POOL_CHECKER
{
boost::object_pool< T > m_sObjectPool;
template <class Arg1>
T* contruct(Arg1& sArg1)
{
T* temp = m_sObjectPool.construct(sArg1);
return temp;
}
}
MaterialServer.h
class MaterialServer
{
MaterialServer(dword serviceType, std::string path);
Material* NEW_MATERIAL();
}
Material.h
class Material
{
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
Material(MaterialServer* pMatServer);
}
Material.cpp
Material* MaterialServer::NEW_MATERIAL()
{
//Material* returnMaterial = m_poolMATERIAL.construct(this); << error on vs2019, not correct parameter
Material* returnMaterial = m_poolMATERIAL.construct(*this);
}
got first error
boost_1_56\boost\pool\detail\pool_construct_simple.ipp(19,1): error C2664: 'Material::Material(MaterialServer*)': cannot convert argument 1 from 'const T0' to 'MaterialServer *'
ObjectPool.h(68): message : see reference to function template instantiation 'Material *boost::object_pool<T,boost::default_user_allocator_new_delete>::construct<Arg1>(const T0 &)' being compiled
with
[
T=Material,
Arg1=MaterialServer,
T0=MaterialServer
]
should I need upgrade boost version? because previously this code compiled fine on vs2008, but not compiled on vs2019, this c++11 standard so confusing for me
can I get explanation this behavior?
Frankly, this code cannot have compiled under any compiler.
Note: I'm ignoring numerous typos, omitted semi-colons, omitted template declarators, typedefs and access specifiers to focus on the real issues.
You're passing *this which is Material&. However, the contruct [sic] function takes a MaterialServer*.
So, in fact, the commented line was closer, and makes sense IFF it were a member of MaterialServer, not Material.
It would make a lot more sense, logically, for the material server to "create new materials", anyways, and almost works:
class Material {
public:
Material(MaterialServer* pMatServer);
};
class MaterialServer {
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
public:
MaterialServer(dword serviceType, std::string path);
Material* NEW_MATERIAL();
};
Material* MaterialServer::NEW_MATERIAL()
{
Material* returnMaterial = m_poolMATERIAL.construct(this);
return returnMaterial;
}
I say /almost/ because construct takes its argument by mutable reference. That won't compile here (this is NOT a mutable lvalue).
So, fixing that:
template <typename Arg1> T* construct(Arg1 sArg1) {
return m_sObjectPool.construct(sArg1);
}
Or, more generically:
template <typename... Arg> T* construct(Arg&&... sArg) {
return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}
We get "compiling code". We can't link it (the constructors aren't defined).
Adding some more imagined code:
Live On Coliru
#include <boost/pool/object_pool.hpp>
#include <iomanip>
#include <iostream>
#include <string>
#include <atomic>
using dword = uint32_t;
template <typename T> class BOOST_OBJECT_POOL_CHECKER {
boost::object_pool<T> m_sObjectPool;
public:
template <typename... Arg> T* construct(Arg&&... sArg)
{
return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}
};
class MaterialServer; // forward declare
class Material {
public:
Material(MaterialServer* pMatServer);
};
class MaterialServer {
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
dword _serviceType;
std::string _path;
public:
MaterialServer(dword serviceType, std::string path)
: _serviceType(serviceType)
, _path(path)
{
}
Material* NEW_MATERIAL();
dword getServiceType() const { return _serviceType; }
std::string_view getPath() const { return _path; }
};
Material* MaterialServer::NEW_MATERIAL()
{
Material* returnMaterial = m_poolMATERIAL.construct(this);
return returnMaterial;
}
Material::Material(MaterialServer* pMatServer)
{
static std::atomic_int id{0};
std::cout << "Material " << id++ << " from server ("
<< pMatServer->getServiceType() << ", "
<< std::quoted(pMatServer->getPath()) << ")\n";
}
int main() {
MaterialServer a(123, "Material/a/resource");
MaterialServer b(234, "Material/b/resource");
a.NEW_MATERIAL();
a.NEW_MATERIAL();
b.NEW_MATERIAL();
a.NEW_MATERIAL();
}
Prints
Material 0 from server (123, "Material/a/resource")
Material 1 from server (123, "Material/a/resource")
Material 2 from server (234, "Material/b/resource")
Material 3 from server (123, "Material/a/resource")
I know there are a couple other questions on this specific question, but nothing that I can find on it seems to work, so I'm posting my specific code.
Here is the code:
#ifndef __MEMORY_TRACKER_H__
#define __MEMORY_TRACKER_H__
#include <unordered_map>
namespace cige
{
namespace memory
{
class CIGE_API MemoryTracker
{
protected:
typedef struct AllocRecord
{
size_t bytes;
std::string filename;
size_t line;
std::string func;
AllocRecord() :
bytes(0), line(0)
{ }
AllocRecord(size_t sz, const char* file, size_t ln, const char* fun) :
bytes(sz), line(ln)
{
if (file)
filename = file;
if (fun)
func = fun;
}
} AllocRecord;
std::string m_leakFileName;
bool m_dumpToConsole;
typedef std::unordered_map<void*, AllocRecord> AllocMap;
AllocMap m_allocationMap;
size_t m_totalAllocations;
bool m_recordEnable;
protected:
void reportLeaks();
MemoryTracker() :
m_leakFileName("CIGEMemory.log"), m_dumpToConsole(true), m_totalAllocations(0), m_recordEnable(true)
{ }
public:
void setReportFileName(const std::string& name)
{
m_leakFileName = name;
}
const std::string& getReportFileName() const
{
return m_leakFileName;
}
void setReportToConsoleOutput(bool b)
{
m_dumpToConsole = b;
}
bool getReportToConsoleOutput() const
{
return m_dumpToConsole;
}
void setRecordEnable(bool b)
{
m_recordEnable = b;
}
bool getRecordEnable() const
{
return m_recordEnable;
}
size_t getTotalMemoryAllocated() const
{
return m_totalAllocations;
}
void _recordAlloc(void* ptr, size_t sz, const char* file = nullptr, size_t ln = 0, const char* fun = nullptr);
void _recordDealloc(void* ptr);
~MemoryTracker()
{
reportLeaks();
}
static MemoryTracker& get();
};
}
}
#endif // __MEMORY_TRACKER_H__
I'm getting: variable 'cige::memory::CIGE_API cige::memory::MemoryTracker' has initializer but incomplete type at the line with the class declaration. I've looked all over and I cant find any answers that have fixed this issue.
I'm also having the error expected '}' or ',' or ';' before 'protected' at the line with protected, right above the struct.
Any help with either of these two errors would be appreciated.
EDIT: CIGE_API is defined in a separate file (which is included), as __declspec(dllexport).
EDIT2: I fixed my problem (see the answer below). It was basically just Code::Blocks derping out pretty bad.
Looks like CIGE_API is not defined. So compiler try to resolve it like variable declaration class Type Variable {initializer-list}, where Type is CIGE_API and Variable is MemoryTracker.
In other words, syntactically you're predeclaring CIGE_API type and creating variable of this type instead of defining a class.
The definition
class CIGE_API MemoryTracker { ... };
is not valid C++. I guess CIGE_API is a macro defined to an implementation specific extension, but you didn't include the corresponding header which defines that macro.
Ok I ended up fixing my own problem. Code::Blocks wasn't properly finding files that were in my project (about the third time this has happened).
In entirely unrelated news, does anyone know another cross-platform IDE that works well for C++? (I already know about Eclipse).
I am trying to compile solutions and projects on MSVC++ 10 that worked fine in MSVC++ 9, and I am having trouble with it, mostly getting the following message:
error C2888: 'std::hash' : symbol cannot be defined within namespace 'tr1'
on the following code:
namespace std {
namespace tr1 {
template <>
struct hash< Rubedo::eChannelFamily >
{
std::size_t operator()( const Rubedo::eChannelFamily& Key ) const
{
return ( int ) Key;
}
};
}}
I would be perfectly happy if I could do one of the following:
Modify the code to fix the bugs and compile cleanly;
Force the compiler to behave like MSVC++ 9.0.
How would I do something like that?
Thank you very much in advance.
hash is in namespace std in VS2010, as it's part of C++0x's Standard library, not std::tr1. Just remove the tr1 section and the compiler should be fine.
template<> class std::hash< Rubedo::eChannelFamily >>
: public std::unary_function<const Rubedo::eChannelFamily, size_t>
{
public:
size_t operator()(const Rubedo::eChannelFamily& ref) const {
return ( int ) ref;
}
};
This is a fairly trivial modification of a hash I have for my own type which compiles successfully.
You've to inherit unary_function like this and tr1 is not needed anymore,
namespace std
{
template <>
struct hash<Rubedo::eChannelFamily> : public unary_function<Rubedo::eChannelFamily, size_t>
{
size_t operator()(const Rubedo::eChannelFamily& key) const
{
return (size_t) key;
}
};
}