Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have looked at other questions regarding this error, but I so far have not found what looked like the answer to my problem there. I have two classes Message and ColorString. In a method of the former I make several instances of the latter by passing members of Message to the constructor of ColorString
message.hpp
#ifndef __MESSAGE__HPP
#define __MESSAGE__HPP
#if defined __linux || defined __APPLE__
#define UNIXLIKE
#endif
////////////////////////////////////////////////////////////////////////////////
// Message helps organize error and warning messages //
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <sstream>
#include <fstream>
#include "color.hpp"
////////////////////////////////////////////////////////////////////////////////
// MESSSAGE //
////////////////////////////////////////////////////////////////////////////////
class Message
{
////////////////////////////////////////////////////////////////////////////////
public: // types
////////////////////////////////////////////////////////////////////////////////
typedef COLOR::ColorString colstr;
typedef COLOR::ColorID color;
////////////////////////////////////////////////////////////////////////////////
public: // methods
////////////////////////////////////////////////////////////////////////////////
Message(std::ostream& o = std::cerr)
: o(std::cerr)
{
}
////////////////////////////////////////////////////////////////////////////////
Message(const std::string& message,
const std::string& label ="",
const std::string file="",
const int line = -1,
std::ostream& o = std::cerr,
const color c = COLOR::RED
)
: o(std::cerr)
{
}
////////////////////////////////////////////////////////////////////////////////
friend std::ostream& operator<<(std::ostream& o, Message& m)
{
#ifdef UNIXLIKE
colstr lbl(label, c);
colstr msg(message);
colstr ln(linestr);
colstr fl(file);
#else
std::string lbl(label);
std::string msg(message);
std::string ln(linestr);
std::string fl(file);
#endif
o << fl << ln;
if (fl.size() > 0 || ln.size() > 0) o << ": ";
o << lbl << " " << msg << "\n";
o.flush();
return o;
}
////////////////////////////////////////////////////////////////////////////////
private: // methods
////////////////////////////////////////////////////////////////////////////////
void init(const std::string& message,
const std::string& label = "",
const std::string file="",
const int line = -1,
std::ostream& o = std::cerr,
const color c = COLOR::RED)
{
this->message = message;
this->label = label;
this->file = file;
this->line = line;
this->c = c;
if (this->line > -1)
{
std::stringstream ss;
ss << this->line;
ss >> linestr;
}
if (this->file.size() > 0)
{
this->file = this->file+":";
if (this->line > -1)
{
this->file = this->file+linestr; linestr="";
}
}
}
////////////////////////////////////////////////////////////////////////////////
private : // fields
////////////////////////////////////////////////////////////////////////////////
std::string label;
std::string message;
std::string file;
int line;
std::ostream& o;
color c;
std::string linestr;
};
#endif
The constructor of ColorString looks like this:
/**
* #brief constructs a ColorString with color #p c and the string
* #p s.
* #param s string to wrap
* #param c color to print #p s in
* #param bold determines whether #p s will be printed bold
*/
ColorString(str s, ColorID c=DEF, bool bold=1)
:string(s),
color(c),
bold(bold)
{
}
The part causing the errors is this:
#ifdef UNIXLIKE
colstr lbl(label, c);
colstr msg(message);
colstr ln(linestr);
colstr fl(file);
#else
Errors:
message.hpp:58:20: error: invalid use of non-static data member 'label'
colstr lbl(label, c);
^~~~~
message.hpp:58:27: error: invalid use of non-static data member 'c'
colstr lbl(label, c);
^
message.hpp:59:20: error: invalid use of non-static data member 'message'
colstr msg(message);
^~~~~~~
message.hpp:60:19: error: invalid use of non-static data member 'linestr'
colstr ln(linestr);
^~~~~~~
message.hpp:61:19: error: invalid use of non-static data member 'file'
colstr fl(file);
What's the problem here?
The problem is that you are defining a friend function. Even when you define them "inline" in the class, they are still non-member functions and need an object instance to access their members.
You need to do e.g.
colstr lbl(m.label, m.c);
Related
I would like to know how to read/write a JSON file using C++.
I will be using this file to store player info & setting for a simple game I'm making.
It's nothing fancy, just a console number guessing game, but I just use it to learn stuff.
I have to know how to read & write specific parts of a JSON.
Using a library, it can be done quite easily:
#include <nlohmann/json.hpp>
#include <iostream>
int main() {
// read file
auto json = nlohmann::json::parse("{\"value1\": \"string\"}");
// mutate the json
json["value1"] = "new string";
// write to a stream, or the same file
std::cout << json; // print the json
}
C++ don't have the built-ins for dealing with json. You can implement your own json data structure, or use one available like nlohmann/json or simdjson
You could create your own parser using pure C++ with the standard library only, but I would advise against.
Using struct_mapping it can be done:
#include "struct_mapping/struct_mapping.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
struct Planet
{
std::string name;
double mass;
bool populated;
};
int main()
{
struct_mapping::reg(&Planet::name, "name");
struct_mapping::reg(&Planet::mass, "mass");
struct_mapping::reg(&Planet::populated, "populated");
Planet planet;
auto stream = std::ifstream("planet.json");
struct_mapping::map_json_to_struct(planet, stream);
planet.name = "Mars";
planet.populated = false;
std::ostringstream out_json_data;
struct_mapping::map_struct_to_json(planet, out_json_data, " ");
std::cout << out_json_data.str() << std::endl;
}
Data file example
{
"name": "Earth",
"mass": 1234,
"populated": true
}
I wrapped boost property tree initialized around classes and macros and it's close to type reflection(but it's still missing a reflection library to finish it off).
It Also supports nesting of types something that alot of so called "fantastic json" libraries fall short of when you get into
the nitty gritty.
So say you have a class what you want to serialize or deserialize in JSON:
I'd write in my cpp
class MyClass: public virtual Algorithm::Interface::ISimpleSerializedType
{
public:
int a;
string b;
// could be simplified further via a variadic macro to generate //SimplePropertyTree
virtual Algorithm::Interface::IPropertyTree SimplePropertyTree(Algorithm::Interface::IPropertyTree& pt, bool toPropertyTree)
{
PSER(a, int)
PSER(b, string)
}
};
The JSON would look something like
{
a : "1"
b :"somestring"
}
My read and write unit tests/snippets would look like this:
//write
MyClass entity;
entity.a = 1;
entity.filename = "test.json";
entity.ToFile();
// read
MyClass entity;
entity.filename = "test.json";
entity.FromFile(); // everything is loaded
code for Algorithm::Interface::ISimpleSerializedType
#ifndef I_SIMPLE_SERIALIZED_TYPE_H
#define I_SIMPLE_SERIALIZED_TYPE_H
#include "IType.h"
#include "IFileSerializer.h"
namespace Algorithm
{
namespace Interface
{
// Class contract that exposes common methods for which to extend
class ISimpleSerializedType : public virtual IType,public virtual IFileSerializer
{
public:
virtual IPropertyTree ToPropertyTree(void){
IPropertyTree pt;
return SimplePropertyTree(pt,true);
};
// method which extracts the values from property tree
virtual void FromPropertyTree(IPropertyTree& pt){
auto tree = SimplePropertyTree(pt,false);
pt = tree._pt;
};
protected:
// need to implement this
virtual IPropertyTree SimplePropertyTree(IPropertyTree& pt,bool ToPropertyTree)
{
return pt;
}
};
}
}
#endif
Code For ITYPE
#ifndef ITYPE_H
#define ITYPE_H
#include <sstream>
#include <string>
#include <vector>
#include <string>
#include "IPropertyTree.h"
#include <fstream>
// macross to simplify streaming property tree
#define __str__(s) #s
#define PADD(s) {\
try\
{\
std::string ss = std::to_string(s);\
std::string key = std::string(__str__(s));\
pt.add(key,ss);\
}\
catch (std::exception ex)\
{\
}\
}
#define PADDS(s) {\
try\
{\
std::string key = std::string(__str__(s));\
pt.add(key,s);\
}\
catch (std::exception ex)\
{\
}\
}
#define PADDBASE(BASE){\
auto st = std::string(__str__(BASE));\
auto pt2 = BASE##ToPropertyTree();\
pt.addPropertyTree(st, pt2);\
}
#define PADDMEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
LOGIT1(st)\
auto _pt = membervar.ToPropertyTree();\
pt.addPropertyTree(st, _pt);\
}
// PGET
#define PGET(VAR,type) { std::string s(__str__(VAR));\
VAR = pt.get<type>(s); }
#define PGETBASE(VAR) {\
try\
{\
auto st = std::string(__str__(VAR));\
auto ptBase##VAR = pt.getChild(st); \
VAR##FromPropertyTree(ptBase##VAR);\
}\
catch (...)\
{\
}\
}
#define PGETMEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
auto pt2 = pt.getChild(st);\
membervar.FromPropertyTree(pt2);\
}
///////////////
/// PGET2
#define PGET2(VAR,type) { std::string s(__str__(VAR));\
VAR = pt._pt.get<type>(s); }
#define PGET2BASE(VAR) {\
try\
{\
auto st = std::string(__str__(VAR));\
auto ptBase##VAR = pt._pt.getChild(st); \
VAR##FromPropertyTree(ptBase##VAR);\
}\
catch (...)\
{\
}\
}
#define PGET2MEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
auto pt2 = pt_pt.getChild(st);\
membervar.FromPropertyTree(pt2);\
}
// PSerialize uses a implied type bool ToPropertyTree and pt
#define PSER(VAR,type) if(toPropertyTree) {\
std::cout << "padd" << std::endl;\
PADD(VAR)\
} else {\
std::cout << "pget" << std::endl;\
PGET(VAR,type)\
}
#define PSERS(VAR) if(toPropertyTree) {\
PADDS(VAR)\
} else {\
PGET(VAR,std::string)\
}
#define PSERBASE(VAR)if(toPropertyTree) {\
PADDBASE(VAR)\
} else {\
PGET2BASE(VAR)\
}
#define PSERMEMBER(membervar)if(toPropertyTree) {\
PADDMEMBER(membervar) \
} else {\
PGET2MEMBER(membervar) \
}
namespace Algorithm
{
namespace Interface
{
// Class contract that exposes common methods for which to extend
class IType
{
public:
IType() {};
// causes problems with hiberlite when you derive it
// from MVC so omitting this
// IType(IType& rhs) { *this = rhs; }
virtual ~IType(){}; // destructor
// methods don't communicate tho the key just the value
// like stl containers returns size of type
virtual size_t size(void){ return sizeof(IType);};
// says the maximum size of the type
virtual size_t max_size(void) { return sizeof(IType); };
virtual void ToString(char* data,size_t& dataSize){ /* not implemented*/ };
virtual void FromString(char* data,size_t& dataSize){};
IType& operator=(const IType& rhs){
std::string s;
IType& rhsRef = const_cast<IType&>(rhs);
size_t size = rhsRef.size();
s.resize(size);
rhsRef.ToString(const_cast<char*>(s.c_str()), size);
FromString(const_cast<char*>(s.c_str()),size);
return *this;
};
// must be friended methods
// istream extraction operators terminated by std::endl for each respective subtype
// ostream extraction operators terminated by std::endl for each respective subtype
// encode the stream to stream with variable name + value name. Useful for key value streams;
virtual IPropertyTree ToPropertyTree(void){
IPropertyTree pt;
return pt;
};
// method which extracts the values from property tree
virtual void FromPropertyTree(boost::property_tree::ptree& typesEncodedInAPropertyTree){
IPropertyTree pt;
pt._pt = typesEncodedInAPropertyTree;
FromPropertyTree(pt);
};
// method which extracts the values from property tree
virtual void FromPropertyTree(IPropertyTree& typesEncodedInAPropertyTree) {
};
// call a serializer here
// method instructs how to write to file by calling the approppriate serializer
virtual void ToFile(void){
};
virtual void FromFile(void) {};
virtual std::string TypeName(void) { return ""; };
protected:
inline bool exist(const std::string& name)
{
std::ifstream file(name);
if (!file) // If the file was not found, then file is 0, i.e. !file=1 or true.
return false; // The file was not found.
else // If the file was found, then file is non-0.
return true; // The file was found.
}
};
}
}
#endif
Code For IPropertyTree
#ifndef I_PROPERTY_TREE_H
#define I_PROPERTY_TREE_H
#include <boost/property_tree/ptree.hpp>
#include <memory>
#include <map>
#include <string>
#include <vector>
#include <iostream>
namespace Algorithm
{
namespace Interface
{
class IPropertyTree
{
const std::string attributePrefix = ".<xmlattr>."; // attribute prefix to reference a attribute within boost property tree
// https://stackoverflow.com/questions/3690436/how-are-attributes-parsed-in-boost-propertytree
std::string BuildAttributeInsertionKey(std::string& key, std::string& attributeKey) { return key + attributePrefix + attributeKey; };
public:
boost::property_tree::ptree _pt; // good reference reading https://theboostcpplibraries.com/boost.propertytree
const IPropertyTree& operator=(const IPropertyTree& pt){
this->_pt = pt._pt;
return *this;};
IPropertyTree(void) :_pt() {};
IPropertyTree(boost::property_tree::ptree& pt) : _pt(pt) {};
// usually only accessed by the serializers don't manually edit this
boost::property_tree::ptree& GetBoostPropertyTree(void) { return _pt; };
#ifdef _WIN32
// key/value get and set
template <class T>
void add(std::string& key, T& value)
{
_pt.put(key, value);
};
#else
template <class T>
void add(std::string key, T value)
{
_pt.put(key, value);
};
#endif
template <class T>
T get(std::string& path) {
return _pt.get<T>(path);
};
// attribute get/set
template <class T>
void addAttribute(std::string& keyName, std::string& attributeKey, T& attributeValue) {
_pt.add(BuildAttributeInsertionKey(keyName, attributeKey), std::to_string(attributeValue));
}
IPropertyTree getChild(std::string& key)
{
return IPropertyTree(_pt.get_child(key));
}
template <class T>
T getAttribute(std::string& keyPath, std::string& attributeName) {
return _pt.get<T>(BuildAttributeInsertionKey(keyPath, attributeName));
}
void addPropertyTree(std::string& keyOfChildTree,IPropertyTree& tree)
{
_pt.add_child(keyOfChildTree,tree.GetBoostPropertyTree());
};
void addAttribute(std::string& keyName,std::string& attributeKey, std::string& attributeValue)
{
_pt.add(BuildAttributeInsertionKey(keyName,attributeKey), attributeValue);
};
};
}
}
#endif
Code For IFileSerializer
#ifndef I_FILE_SERIALIZER_H
#define I_FILE_SERIALIZER_H
#include "IJSONSerialize.h"
#include "IType.h"
#include "../../Tools/Diagnostics/Logger/Logger.h" // this uses LOGIT but you can just replace with std::cout
#include <cstdint>
#include <cstdlib>
#include <string>
namespace Algorithm
{
namespace Interface
{
class IFileSerializer;
// a Serializer for JSON
class IFileSerializer : public virtual Algorithm::Interface::IType
{
public:
std::string filename;
IFileSerializer(void):Algorithm::Interface::IType(),filename(){};
virtual void ToFile(void)
{
std::string msg = TypeName() + "::ToFile()";
LOGIT1(msg)
std::string testJSON(filename);
auto pt = ToPropertyTree();
msg = TypeName() + "::ToFile() calling IJSON serialize";
LOGIT1(msg)
Algorithm::Interface::IJSONSerialize test(testJSON, pt);
msg = TypeName() + "::ToFile() WriteFile";
LOGIT1(msg)
test.WriteFile();
};
virtual void FromFile(void)
{
auto msg = TypeName() + "::FromFile()\n";
LOGIT1(msg)
std::string testJSON(filename);
auto pt = ToPropertyTree();
Algorithm::Interface::IJSONSerialize test(testJSON, pt);
test.ReadFile();
this->FromPropertyTree(test.GetPropertyTree());
};
virtual Algorithm::Interface::IPropertyTree ToPropertyTree(void) { Algorithm::Interface::IPropertyTree pt; return pt;};
// method which extracts the values from property tree
virtual void FromPropertyTree(Algorithm::Interface::IPropertyTree& pt) {};
void ParseServerArgs(char** argv, int argc){
std::string msg2="IFileSerializer::ParseServerArgs";
LOGIT1(msg2)
filename = "config.json";
if(exist(filename))
{
std::string msg = "IFileSerializer::Calling FromFile";
LOGIT1(msg)
FromFile();
}
else
{
std::string msg = "IFileSerializer::Calling ToFile";
LOGIT1(msg)
ToFile(); // write it back so next time you can feed in the json
}
};
}; // end class
}
}
#endif
IJSONSerialize Code
#ifndef IJSONSERIALIZE_H
#define IJSONSERIALIZE_H
#include <string>
#include <vector>
#include <iostream>
#include <boost/property_tree/json_parser.hpp>
#include "IPropertyTree.h"
namespace Algorithm
{
namespace Interface
{
// object that provides facilities to serialize JavaScript Object Notation(JSON)
// citation: https://stackoverflow.com/questions/4586768/how-to-iterate-a-boost-property-tree
class IJSONSerialize
{
IPropertyTree _pt;
std::string _filename;
public:
IJSONSerialize(const std::string& filename, IPropertyTree& pt):_pt(pt),_filename(filename){
};
virtual void WriteFile(void){
try
{
boost::property_tree::json_parser::write_json(_filename, _pt.GetBoostPropertyTree());
}
catch(std::exception ex)
{
std::cerr << "can't write json file " << _filename;
}
};
virtual void WriteAsAString(std::string& outString)
{
std::stringstream ss;
boost::property_tree::write_json(ss, _pt.GetBoostPropertyTree());
outString = ss.str();
};
virtual void ReadFile(void){
try
{
boost::property_tree::read_json(_filename, _pt.GetBoostPropertyTree());
}
catch(const boost::property_tree::json_parser_error &jpe)
{
//do error handling
std::cerr << "can't read json file " << _filename <<jpe.what();
}
};
virtual void ReadFromString(std::string& s){
try
{
std::stringstream ss;
ss << s;
auto pt = _pt.GetBoostPropertyTree(); boost::property_tree::json_parser::read_json(ss, pt);
}
catch(std::exception)
{
}
};
virtual std::string WriteToString(void){
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss,_pt.GetBoostPropertyTree());
return ss.str();
};
// use to retrieve all the values but
virtual IPropertyTree& GetPropertyTree(void){
return _pt;
};
};
}
}
#endif
If any code missing you can find it in my bitbucket crossplatform C++ network template that's built
on top of boost asio. The code is here: https://bitbucket.org/ptroen/crossplatformnetwork/src/master/
And again if you missed the comment and don't want to use LOGIT you can just find and replace with std::cout
Note code above is working but if you study enough their is some tech debt that could be optimized even more like reflection
Anyways hope you find this useful
I would like to create a class and enum to handle errors in my project. As of now I am doing it in the below way.
enum class eErrorType
{
eJsonFileNotFound = 0,
eJsonInvalidFormat,
eJsonKeyNotFound,
eJsonEmptyArray,
eNoError,
eCustom
};
class Error
{
public:
// Constructors
Error() { errorType = eErrorType::eNoError; message = ""; }
Error(eErrorType type) { errorType = type; SetMessage(type); }
Error(std::string msg) { errorType = eErrorType::eCustom; message = msg; }
// Public Methods
std::string getErrMessage() { return message; }
private:
eErrorType errorType;
std::string message;
void SetMessage(eErrorType type)
{
switch (type)
{
case eErrorType::eJsonFileNotFound: message = "Json file not found"; break;
case eErrorType::eJsonInvalidFormat: message = "Invalid json file"; break;
case eErrorType::eJsonKeyNotFound: message = "Specified key is not found in json"; break;
case eErrorType::eJsonEmptyArray: message = "No elements in json array"; break;
case eErrorType::eNoError: message = "Entry contained an attempt to divide by zero!"; break;
default: message = ""; break;
}
}
};
int main()
{
try
{
//open json file. If file open failed, throw error
throw eErrorType::eJsonFileNotFound;
//parse json file. If parsing failed, throw error
throw eErrorType::eJsonInvalidFormat;
//check for particular key in the json. If not found, throw error
throw eErrorType::eJsonKeyNotFound;
}
catch (eErrorType errCode)
{
Error errObj(errCode);
std::cout << errObj.getErrMessage() << std::endl;
}
return 0;
}
I would like some suggestions for improvements. Is there any better way of doing it or any language based features are available to achieve this.
For custom errors you can inherit from std::exception, override exception methods and implement your own stuff, example:
#include <exception> // std::exception
//
// custom exception class
//
class error final :
public std::exception
{
public:
error(const char* description, short code = -1) throw() :
description(description), code(code) { }
const char* what() const throw() override
{
return description;
}
short Code() const throw()
{
return code;
}
error(error&& ref)
: description(ref.description), code(ref.code) { }
error& operator=(error&&)
{
return *this;
}
error(const error& ref)
: description(ref.description), code(ref.code) { }
private:
const char* description;
const short code;
error& operator=(const error&) = delete;
};
Define a macro to show the filename where the error occured:
#include <cstring> // std::strrchr
// Show only file name instead of full path
#define __FILENAME__ (std::strrchr(__FILE__, '\\') ? std::strrchr(__FILE__, '\\') + 1 : __FILE__)
Define universal function to show the error (followin implemetation shows message box but you can redefine it for console program)
#include <string>
#include <windows.h>
#include <codecvt> // string conversion std::wstring_convert and std::codecvt_utf8
//
// converts string or const char* to wstring
//
std::wstring stringToWstring(const std::string& t_str)
{
//setup converter
typedef std::codecvt_utf8<wchar_t> convert_type;
std::wstring_convert<convert_type, wchar_t> converter;
//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
return converter.from_bytes(t_str);
}
//
// Set error message to your liking using error class
// and show message box, this function is also used to pass in
// std::exception objects
//
template <typename ExceptionClass>
void ShowError(
HWND hWnd,
ExceptionClass exception,
const char* file,
int line,
long info = MB_ICONERROR)
{
std::string error_type = TEXT("Rutime Error");
std::string error_message = TEXT("File:\t");
#ifdef UNICODE
error_message.append(stringToWstring(file));
#else
error_message.append(file);
#endif // UNICODE
error_message.append(TEXT("\r\nLine:\t"));
error_message.append(std::to_string(line));
error_message.append(TEXT("\r\nError:\t"));
#ifdef UNICODE
error_message.append(stringToWstring(exception.what()));
#else
error_message.append(exception.what());
#endif // UNICODE
// Show error message
MessageBox(hWnd,
error_message.c_str(),
error_type.c_str(), static_cast<UINT>(MB_OK | info));
}
You then show the error like this:
ShowError(nullptr, error("You error message"), __FILENAME__, __LINE__);
For Win32/COM error types the function can be overloaded like this:
#include <comdef.h> // _com_error
#include <windows.h>
#include <string>
//
// Format error code into a string and show message box
// COM and System errors
//
void ShowError(HWND hWnd, const char* file, int line, HRESULT hr = S_OK)
{
string error_type = TEXT("Rutime Error");
string error_message = TEXT("File:\t");
#ifdef UNICODE
error_message.append(stringToWstring(file));
#else
error_message.append(file);
#endif // UNICODE
error_message.append(TEXT("\r\nLine:\t"));
error_message.append(std::to_string(line));
error_message.append(TEXT("\r\nError:\t"));
// If HRESULT is omited or S_OK
// format last error code message
if (hr == S_OK)
{
LPVOID lpBuff = nullptr;
DWORD dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
GetLastError(),
0,
reinterpret_cast<LPTSTR>(&lpBuff),
0,
nullptr);
// If the function succeeds, the return value is
// the number of TCHARs stored in the output buffer
if (dwChars)
{
error_message.append(reinterpret_cast<LPCTSTR>(lpBuff));
}
else // If the function fails, the return value is zero
{
error_message.append(TEXT("Unknown Error\t"));
error_message.append(to_string(GetLastError()));
}
// Free the buffer allocated by FormatMessage
LocalFree(lpBuff);
}
else // Format com error code into a message
{
_com_error err(hr);
error_message.append(err.ErrorMessage());
}
// Play the sound and show error message
MessageBox(hWnd,
error_message.c_str(),
error_type.c_str(), MB_OK | MB_ICONERROR);
}
The function is called slight differently for system errors:
ShowError(nullptr, __FILENAME__, __LINE__); // type hresult if needed
edit:
I copied the code from my project, and currently std::to_string where mentioned works only for ANSI version, you need to modify ShowError function to conditionaly use std::to_wstring for unicode.
Also string inside ShowError function is ANSI string, you can conditionally use wstring or define a macro for string if you wan't like this:
#ifdef UNICODE
typedef std::wstring string;
#else
typedef std::string string;
#endif // UNICODE
also for to_string if you wish:
// conditionaly use string or wide string
#ifdef UNICODE
#define to_string std::to_wstring
#else
#define to_string std::to_string
#endif // UNICODE
You can also implement enum class code types and pass them to exception class as second or 3rd additional argument and implement showing the custom error code if you wish to avoid typing error message for every separate function call.
Also note that ShowError function can be used for std errors inside catch statement, where you simply pass std error object like this for example:
try
{
// example, or do some heavy memory allocation here to throw
throw std::bad_alloc;
}
catch(std::bad_alloc& err);
{
ShowError(nullptr, err, __FILENAME__, __LINE__);
}
This approach can be extended to modify the function to also format NTSTATUS messages
For complete list of possible error messages in Win32 see this.
For additional information on functions used in above code see following link:
FormatMessage function
GetLastError function
Some of the code has been copied from this site ex:
Convert to wstring
Show only file name
Format COM Error code
Lets start with the headers.
#include <system_error> // For std::error_code
#include <exception> // For std::exception
#include <iostream> // To print example output
Often you are stuck with some macros (could be constexpr int's)
#define FOO_ERROR1 1
#define FOO_ERROR2 2
You should be working in a namespace, lets use n here.
namespace n {
Step 1. define an enum type (you might already HAVE an enum, which is good).
enum class Error {
XE_FOO_ERROR1 = FOO_ERROR1, // XE_ is a random prefix to distinguish it from the macro FOO_ERROR1.
XE_FOO_ERROR2 = FOO_ERROR2
};
Step 2. define the following functions that will be found through ADL (Argument-dependent lookup). This is why the namespace (n) should be very specific for this error type. As an example, the namespace that I use for errors of my xcb system is xcb::errors::org::freedesktop::xcb. Just n is probably too short, and we should be using foo anyway, but I think it is less confusing for the example to use different names.
std::string to_string(Error code); // You probably want those enums to be convertible to strings with `to_string`.
std::ostream& operator<<(std::ostream& os, Error code); // In order to print the enum's to an ostream.
inline char const* get_domain(Error) { return "foo:org.freedesktop.foo.Error"; } // An error domain string.
std::error_code make_error_code(Error code) noexcept; // Converting the Error to a std::error_code.
} // namespace n
Step 3. register n::Error as valid error code.
namespace std {
template<> struct is_error_code_enum<n::Error> : true_type { };
} // namespace std
And yes, it is legal to define this in namespace std. It is what is intended by the standard.
Next, lets define the above functions in our .cpp file:
namespace n {
// Implement to_string
std::string to_string(Error code)
{
#if 0
switch(code)
{
case Error::XE_FOO_ERROR1:
return "FOO_ERROR1";
case Error::XE_FOO_ERROR2:
return "FOO_ERROR2";
}
return "Never reached";
#else
// Or if you use magic_enum (https://github.com/Neargye/magic_enum), we can use the simple:
auto sv = magic_enum::enum_name(code);
sv.remove_prefix(3); // Remove "XE_" from the name.
return std::string{sv};
#endif
}
// Implement operator<<
std::ostream& operator<<(std::ostream& os, Error code)
{
return os << to_string(code);
}
Before we can define make_error_code we first need to define the error category (this is still in that same .cpp file!):
namespace {
struct FooErrorCategory : std::error_category
{
char const* name() const noexcept override;
std::string message(int ev) const override;
};
char const* FooErrorCategory::name() const noexcept
{
return "n::Error"; // Can be anything you want.
}
std::string FooErrorCategory::message(int ev) const
{
auto error = static_cast<Error>(ev);
return to_string(error);
}
FooErrorCategory const theFooErrorCategory { };
} // namespace
And now we can define make_error_code.
std::error_code make_error_code(Error code) noexcept
{
return std::error_code(static_cast<int>(code), theFooErrorCategory);
}
} // namespace n
In order to support exceptions we need some exception class that supports std::error_code. This is a general class thus, not something specific to one n::Error enum. Personally I use a specialized system that you can find here, but lets just code something minimal for this example (this is the header file):
namespace errors {
struct ErrorCode : public std::exception
{
std::error_code m_ec;
char const* m_text;
ErrorCode(std::error_code ec, char const* text) : m_ec(ec), m_text(text) {}
void print_on(std::ostream& os) const;
};
inline std::ostream& operator<<(std::ostream& os, ErrorCode const& ec)
{
ec.print_on(os);
return os;
}
} // namespace errors
And the .cpp file
namespace errors {
void ErrorCode::print_on(std::ostream& os) const
{
os << m_text << ": " << m_ec.message() << " [" << m_ec << "]";
}
} // namespace errors
Finally, here is some code to test the above.
You can also find this complete example on wandbox.
int main()
{
// A test enum error code.
n::Error error = n::Error::XE_FOO_ERROR2;
// We want to be able to use to_string.
using std::to_string; // Fall back (that we are not using here).
std::cout << to_string(error) << std::endl;
// We want to be able to print an Error.
std::cout << error << std::endl;
// We want to be able to convert the error to a std::error_code.
std::error_code ec = error;
// We want to be able to print that error_code.
std::cout << ec << " [" << ec.message() << "]\n";
// You can convert a macro (or int) value to the enum type.
n::Error e1 = static_cast<n::Error>(FOO_ERROR1);
// We want to be able to throw 'Error' values.
try
{
throw errors::ErrorCode(e1, "Some text");
}
catch (errors::ErrorCode const& error)
{
std::cout << "Caught: " << error << std::endl;
}
}
Which outputs
FOO_ERROR2
FOO_ERROR2
n::Error:2 [FOO_ERROR2]
Caught: Some text: FOO_ERROR1 [n::Error:1]
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I want to make a custom String class for C++. But when I do this:
g++ test.cpp sys/Base.h sys/Base.cpp
I get this error:
sys/Base.cpp: In function 'const char* Base::toChar()':
sys/Base.cpp:57:13: error: 'strval' was not declared in this scope
return strval;
^
sys/Base.cpp: In function 'std::string Base::toStr()':
sys/Base.cpp:60:20: error: 'strval' was not declared in this scope
return string(strval);
^
test.cpp
#include "sys/Base.h"
int main() {
Base::write("Hello there.\n");
return 0;
}
sys/Base.h
// Header file handling
#ifndef ARAVK_BASE_H
#define ARAVK_BASE_H
// Includes
#include <string>
// Global variables
#define EXIT_YAY 0
#define EXIT_ERR 1
using namespace std;
namespace Base {
// Classes:
class String {
static const char* strval;
public:
// Constructors:
String();
String(char[]);
String(const char*);
String(string);
// Destructors:
~String();
// Operators:
// =
void operator=(const String&);
void operator=(const char*&);
void operator=(const string&);
// Conversion:
const char* toChar() const;
string toStr() const;
};
// Functions:
// Input-Output:
// Write:
void write(String);
void write(string);
void write(const char*);
// Read:
String read();
// Executing:
String run(String);
}
#endif
sys/Base.cpp
// Including
#include "Base.h"
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
// Global variables
#define EXIT_ERR 1
#define EXIT_YAY 0
/* ------------------------ */
using namespace std;
namespace Base {
// Classes
// String functions
// Constructors
String::String() {
const char* strval = "";
}
String::String(const char* str) {
const char* strval = str;
}
String::String(string str) {
const char* strval = str.c_str();
}
String::String(char str[]) {
const char* strval = str;
}
// Destructors
String::~String() {
delete strval;
}
// Operators
// =
void String::operator=(const String &strp) {
strval = strp.toChar();
}
void String::operator=(const char* &strp) {
strval = strp;
}
void String::operator=(const string &strp) {
strval = strp.c_str();
}
// Conversion:
const char* toChar() {
return strval;
}
string toStr() {
return string(strval);
}
// Functions:
// Input-Output:
// Write
void write(String str) { printf(str.toChar()); }
void write(const char* str) { printf(str); }
void write(string str) { printf(str.c_str()); }
// Read
String read() { char str[100]; scanf("%s", str); return String(str); }
//TODO: More to come
// Executing
/*String run(String command) {
const char* cmd = command.toChar();
char buffer[128];
string result = "";
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (!pipe) throw runtime_error("popen() failed!");
while (!feof(pipe.get())) {
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
return String(result);
}*/
String run(String command) {
char buffer[128];
std::string result = "";
const char* cmd = command.toChar();
FILE* pipe = popen(cmd, "r");
if (!pipe) throw std::runtime_error("popen() failed!");
try {
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
} catch (...) {
pclose(pipe);
throw;
}
pclose(pipe);
return String(result);
}
}
I'm not sure why this is happening. I think it's related to how I've declared/defined the const char* 'strval'. Can anybody help?
P.S: If the answer is too big, this project is on Github: AravK/C-Applications
Let's take a look at your constructor:
String::String() {
const char* strval = "";
}
This declares a local variable called strval. The variable is local to the constructor; it doesn't exist once execution of the constructor completes.
What you need instead is a member variable - declare it inside the class, but not inside a member method or constructor. In fact, you have already defined it as such in the header file:
class String {
static const char* strval;
So, remove the const char * from your constructor and add a class qualifier, so that the line becomes an assignment to the existing variable, rather than creation of a local:
String::String() {
String::strval = "";
}
And also change the return statement that is giving you the error:
return String::strval;
Or perhaps - and this is likely what you really wanted - remove the static qualifier from the variable definition, and change the constructor instead to just:
String::String() {
strval = "";
}
Furthermore, your destructor incorrectly deletes data that was not necessarily dynamically allocated, or which may belong to another object:
String::~String() {
delete strval;
}
This requires re-working. At the moment the simplest solution is to remove the delete strval altogether.
Your read() function potentially instigates a buffer overflow, by using scanf("%s") with a fixed size buffer and unknown input size:
char str[100]; scanf("%s", str); return String(str);
Finally, your command line:
g++ test.cpp sys/Base.h sys/Base.cpp
... should not include the header file (Base.h). You are specifying the units you want compiled, and Base.h is already included in Base.cpp; it is not a standalone unit that should be compiled invidually.
yes you did not define the variable in your class as a field.
there is 3 locals déclaration in your constructors.
just add it the way you have done in the header.
static const char* strval
and remove the définition in your constructors. Just keep the assignement part.
regards
I'm create my own LOGGER, where I use an additional class for overload macro.
There is #define qlcd MacroCall(QLC::Debug), so i can use logger like this: qlcd << message;
It's ok, but when i try use qlcd("log name") i got an error. Look minimal code (no macro for simplify):
#include <QVariant>
#include <QDebug>
class QLC
{
public:
// Error types
enum LevelType{
Debug=0, // Debug
Error=1, // Error
WTF = 2 // WTF???
} level;
QString logger;
// Constructors
QLC(QLC::LevelType l)
:level(l), logger(":")
{}
QLC(QLC::LevelType l, QString log)
:level(l), logger(log)
{}
// OPERATOR <<
QLC& operator<<(const QVariant var){
qDebug() << "(" + QString::number(level) + ")" << logger << var;
}
};
class MacroCall
{
QLC::LevelType level;
public:
MacroCall()
:level(QLC::Debug){}
MacroCall(int i)
:level(QLC::WTF){}
MacroCall(QLC::LevelType l)
:level(l){}
QLC operator()(){
return QLC(level);
}
QLC operator()(QString log){
return QLC(level, log);
}
};
int main(int argc, char*argv[])
{
MacroCall()("WorkLog") << "No level, yes logname";
MacroCall(QLC::Error)() << "No logname, yes level";
MacroCall a(QLC::Error);
a("WorkLog") << "Logname and level at different lines";
// GET READY!
// INT as level and logname:
MacroCall(2)("WorkLog") << "WTF?? It works!";
//MacroCall(QLC::WTF)("NotWorkLog") << "It's not work!!!!!!";
// NOT WORK: error: invalid use of qualified-name 'QLC::WTF'
// Qt 4.8.3
return 0;
}
The code
MacroCall(QLC::WTF)("NotWorkLog")
is interpreted as declaration of a variable:
MacroCall QLC::WTF("NotWorkLog")
Example:
class A
{
public:
enum E {
x=1
};
public:
A(E) {}
void operator()(int) const { }
};
class B {};
void f()
{
(A(A::x))(1); // Ok
A{A::x}(1); // Ok
A(a)(A::x); // Ok
A::E a; // ‘a’ has a previous declaration as ‘A a’
A(A::x)(1); // invalid use of qualified-name ‘A::x’
B(b)(A::x); // no matching function for call to ‘B::B(A::E)’
}
The code you gave compiles (except that the method QLC& operator<<(const QVariant var) has to return something), eventhough I'm not sure of how it's supposed to be used.
My guess is that your 2 classes are defined in different headers and an include is missing. Does Macrocall header include QLC header ?
when compile, it occurs an error:
PagingInfo.hpp:35: error: ‘StringBuilder’ was not declared in this scope.
I have inlude the right head file, but why compiler can not find the difinition of StringBuilder?
Utils.hpp:
#ifndef LIBFACEBOOKCPP_UTILS_H_
#define LIBFACEBOOKCPP_UTILS_H_
template<class TData, class TStr>
inline TData fromString(const TStr &str)
{
std::stringstream oss;
oss << str;
TData t;
oss >> t;
return t;
}
class StringBuilder
{
public:
inline operator const std::string () const
{
return oss.str();
}
private:
std::ostringstream oss;
};
#endif // LIBFACEBOOKCPP_UTILS_H_
PagingInfo.hpp
#ifndef LIBFACEBOOKCPP_PAGING_INFO_H_
#define LIBFACEBOOKCPP_PAGING_INFO_H_
#include "Utils.hpp"
namespace LibFacebookCpp
{
struct PagingInfo
{
PagingInfo(unsigned int offset_, unsigned int limit_) : offset(offset_), limit(limit_) { }
bool IsValid() const { return 0 != limit; }
void GetUri(Uri *uri) const
{
LIBFACEBOOKCPP_ASSERT(uri);
uri->query_params["limit"] = StringBuilder() << offset;
uri->query_params["offset"] = StringBuilder() << limit;
}
...
};
} // namespace LibFacebookCpp
#endif // LIBFACEBOOKCPP_PAGING_INFO_H_
When I add enough skeleton code to get this down to just your issue in ideone, I get a different error:
prog.cpp: error: no match for 'operator<<' in 'StringBuilder() << ((const LibFacebookCpp::PagingInfo*)this)->LibFacebookCpp::PagingInfo::offset'
Your StringBuilder class does not have a << operator defined. In order to use:
StringBuilder() << offset;
You will need to define one.
Between you and me, there are about 15 overloads of that operator for stringstreams (one for every primitive type). It would be a massive waste of time to reimplement all of them. Just use a stringstream.