I try to write a simple Logger but the ofstream writes hex instead of the characters to the file.
Definition:
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#define LOG Logger::getInstance()
class Logger
{
public:
static Logger m_instance;
static Logger &getInstance()
{
if (m_logfile == nullptr)
{
m_logfile = new std::ofstream(m_logfile_string.c_str(),
std::ofstream::out | std::ofstream::app);
}
return m_instance;
}
Logger &operator<<(const std::string &c);
Logger &operator<<(const char c[]);
private:
static std::ofstream *m_logfile;
static std::string m_logfile_string;
Logger() {};
Logger(const Logger &) = delete;
Logger(Logger &&other) = delete;
Logger &operator=(const Logger &other) = delete;
Logger &operator=(Logger &&other) = delete;
~Logger()
{
if (m_logfile != nullptr)
m_logfile->close();
};
std::string currentDateTime() const;
};
Impl.
#include "Logger.h"
#include <iostream>
#include <ctime>
Logger Logger::m_instance;
std::ofstream *Logger::m_logfile = nullptr;
std::string Logger::m_logfile_string = "log.txt";
Logger &Logger::operator<<(const std::string &c)
{
this->operator<<(c.c_str());
return *this;
}
Logger &Logger::operator<<(const char c[])
{
std::cout << currentDateTime() << " - "
<< c << std::endl;
m_logfile->operator<<(c);
return *this;
}
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
std::string Logger::currentDateTime() const
{
auto now = time(nullptr);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
return buf;
}
Usage:
#include "Logger.h"
void main()
{
LOG << "started"; // Logger::getInstance() << "started";
}
Outcome:
00007FF696EF3C00 in the log.txt The console output is right.
Whats going wrong here?
You use member function of iostream:
m_logfile->operator<<(c);
There is no member function operator<<(char* c), but there is operator<<(void* p), so pointer is implicitly converted. See documentation on ostream.
Operators for char* are not class member functions:
ostream& operator<< (ostream& os, const char* s);
See here: operator<< (ostream)
So you need this code:
operator<<(*m_logfile, c);
Or much more cleaner:
(*m_logfile) << c;
Test example:
#include <iostream>
int main() {
std::cout.operator<<("test");
operator<<(std::cout, "test");
std::cout << "test";
}
Prints 0x400944testtest.
If you use
(*m_logfile)<<c;
instead of
m_logfile->operator<<(c);
It will work.
Reason:
Your syntax calls the member function ostream::operator<<() which is not defined for char* nor for string. It's only defined for void* which always displays address in hex.
The classic syntax calls here the non member function ostream std::operator<<(...) which has overloads for string and char*
Related
#include <iostream>
#include <fstream>
#include <string>
class SychronizedFileWriter : public std::fstream {
//std::mutex _mutex;
public:
SychronizedFileWriter(std::string&& filePath);
virtual ~SychronizedFileWriter();
bool is_open() const;
// SychronizedFileWriter& operator<<(const char* s);
// SychronizedFileWriter& operator<<(SychronizedFileWriter& sfw, const signed char* s);
// SychronizedFileWriter& operator<<(SychronizedFileWriter& sfw, const unsigned char* s);
};
SychronizedFileWriter::SychronizedFileWriter(std::string&& filePath)
{
std::fstream::open(filePath, std::ios_base::app);
}
SychronizedFileWriter:: ~SychronizedFileWriter()
{
std::fstream::close();
}
bool
SychronizedFileWriter::is_open() const
{
return std::fstream::is_open();
}
template<typename T, typename S>
T& operator<<(T& fs, const S* s)
{
std::cout << "im here\n";
{
// Take mutex lock
fs.std::fstream::operator<<(s);
}
return fs;
}
int main(int argc, char *argv[])
{
std::ios_base::sync_with_stdio(true);
SychronizedFileWriter sfw(std::string("./test.txt"));
std::cout << "open: " << std::boolalpha << sfw.is_open();
sfw << "Hello, Worked!!!!" << "\n";
exit(0);
}
Code compiled successfully. However, "text.txt" does not contain the string "Hello, Worked!!!!" but it is empty. My purpose is just to use this class as a wrapper to operator<< so that i can use mutex to synchronize writing to the same file by different threads.
Thanks in Advance and highly appreciate your help.
Static1.hpp
#include <string>
class Static1
{
public:
static const std::string my_string;
};
Static1.cpp
#include "Static1.hpp"
const std::string Static1::my_string = "aaa";
Static2.hpp
#include <string>
class Static2
{
public:
static const std::string my_string;
};
Static2.cpp
#include "Static2.hpp"
const std::string Static2::my_string = Static1::my_string;
main.cpp
#include "Static2.hpp"
#include <iostream>
int main(argc int, char** argv)
{
cout << to_string(Static2::my_string == "aaa") << endl;
return 0;
}
If I put add_executable(printMyString main.cpp Static2.cpp Static1.cpp) in my CMakeLists.txt, I get
0
while add_executable(printMyString main.cpp Static2.cpp Static1.cpp) gives me the expected behavior of
1
To make my code easier to maintain (so that I don't need to keep track of the order I list my source files), is there any way I can ensure that I get the behavior where Static2::my_string == "aaa"?
You are experiencing effects of a static initialization order fiasco.
The usual work-around is to substitute your static variables with functions that have a static variable in the scope, initialize, and return it.
Here is how it could be done for your example: Live Example (order1)
Live Example (order2)
class Static1
{
public:
static std::string my_string();
};
...
std::string Static1::my_string()
{
static const std::string my_string = "aaa";
return my_string;
}
...
class Static2
{
public:
static std::string my_string();
};
...
std::string Static2::my_string()
{
static const std::string my_string = Static1::my_string();
return my_string;
}
...
std::cout << std::to_string(Static2::my_string() == "aaa") << std::endl;
I have 3 c++ files, instrument.h, percussion.h, and instrumentApp.cpp. Instrument.h is the base class and percussion.h inherits it. Percussion objects are defined and implemented in the instrumentApp.cpp class. Whenever I run instrumentApp.cpp, I get the segmentation fault error.
I have managed to trace the cause of the error to the overloaded << operator function in percussion.h where I am calling a method of the base class instrument.h. For some reason, my code is unable to call methods of the base class and I don't know why. Can you please help me?
Here is the instrument.h class
#ifndef INSTRUMENT_H
#define INSTRUMENT_H
class Instrument{
private:
std::string name;
std::string sound;
std::string lowRange;
std::string highRange;
public:
Instrument(std::string name, std::string sound, std::string lowRange, std::string highRange){
this->name = name;
this->sound = sound;
this->lowRange = lowRange;
this->highRange = highRange;
}
std::string getName() const{
return this->name;
}
std::string play()const {
return this->sound;
}
std::string getLowRange() const{
return this->lowRange;
}
std::string getHighRange() const{
return this->highRange;
}
bool isWind();
bool isWoodWind();
bool isBrass();
bool isKeyboard();
bool isPercussion();
bool isStrings();
friend std::ostream &operator <<(std::ostream &os, const Instrument &instrument){
}
};
#endif
Here is the percussion.h class
#ifndef PERCUSSION_H
#define PERCUSSION_H
#include "instrument.h"
class Percussion : public Instrument{
private:
bool struck;
public:
Percussion(std::string name, std::string sound, std::string lowRange, std::string highRange, bool struck) : Instrument(name,sound,lowRange,highRange){
this->struck=struck;
}
bool isStrucked() const {
return this->struck;
}
bool isPercussion() {
return true;
}
std::string getType() const{
if(this->struck){
return "struck";
}
else{
return "";
}
}
friend std::ostream &operator <<(std::ostream &os, Percussion &percussion){
//The error stems from this line of code
//Apparently, the getName() method in the base class isn't called
os<<percussion.getName();
}
};
#endif
Here is the implementation file instrumentApp.cpp
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include "instrument.h"
#include "percussion.h"
#include "strings.h"
using namespace std;
int main() {
Percussion timpani("timpani", "boom", "D2", "A2", true);
cout << timpani << endl;
Percussion harp("harp", "pling", "Cb1", "F#7", false);
cout << harp << endl;
return 0;
}
The problem here is that I wasn't returning the os object when I overloaded the << operator.
The fix is as follows in the percussion.h file
friend std::ostream &operator <<(std::ostream &os, Percussion &percussion){
os<<percussion.getName();
return os;
}
I'm experiencing troubles with c++ inherrited member function, look at the following code:
binIO_t wtest(path, mode);
const void* Buff = "abcd";
wtest << Buff, 1; //no operator found
wtest.virtIO_t::operator<<(Buff), 1; //works fine
Exact compiler error is:
Error 1 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'void *' (or there is no acceptable conversion) ...
I'm surly missing some subtle decleration yet I fail to find it.
my superclass.h is:
#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <stdio.h>
using namespace std;
class virtIO_t{
private:
virtIO_t();
public:
virtIO_t(string filePath, string fileMode);
~virtIO_t();
virtual virtIO_t& operator >> (void* Buf);
virtual virtIO_t& operator << (const void* Buf);
virtual virtIO_t& operator << (const char val) = 0;
virtual virtIO_t& operator >> (char &val) = 0;
};
and the superclass.cpp is:
#include "stdafx.h"
#include "virtIO_t.h"
virtIO_t::virtIO_t()
{
}
virtIO_t::~virtIO_t()
{
...
}
virtIO_t::virtIO_t(string filePath, string fileMode){
...
}
virtIO_t& virtIO_t::operator << (const void* Buff){
...
}
virtIO_t& virtIO_t::operator >> (void* Buff){
...
}
and the sub.h is:
#pragma once
#include "virtIO_t.h"
class binIO_t : public virtIO_t{
public:
binIO_t(string filePath, string mode);
virtIO_t& operator << (const char val);
virtIO_t& operator >> (char &val);
and the sub.cpp is:
#include "stdafx.h"
#include "binIO_t.h"
binIO_t::binIO_t(string filePath, string mode) : virtIO_t(filePath, (string(mode) + "b").c_str()){}
virtIO_t& binIO_t::operator << (const char val){
...
}
virtIO_t& binIO_t::operator >> (char &val){
...
}
binIO_t declares it's own operator<< which hides operator<<(void*) from base class. Try using virtIO_t::operator<< directive or explicitly define operator<<(void*) in biunIO_t.
Also: , 1 does nothing.
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.