Overload operator<< for text rendering - c++

I want to create a class which would help me with debugging by providing std::cout or QDebug like functionality using a 3D renderer.
I have the following renderer method which I'm using now
IRenderer::renderText(int posX, int posY, const float* color, const char* text, ...);
// E.g.
int i;
float f;
float color[] = {1, 1, 1, 1};
renderer->renderText(50, 50, color, "Float %f followed by int %i", f, i);
This actually works fine, but I wonder if it's possible to create a class which would allow me to do it like this:
debug() << "My variables: " << i << ", " << "f";
I assume there would be a template function which would build the string to pass to renderText() based on input type, but I'm not quite sure how to implement it.

An alternative to Rob's answer is to include an ostringstream in your custom logger class, and use the destructor to do the logging:
#include <iostream>
#include <sstream>
class MyLogger
{
protected:
std::ostringstream ss;
public:
~MyLogger()
{
std::cout << "Hey ma, I'm a custom logger! " << ss.str();
//renderer->renderText(50, 50, color, ss.str());
}
std::ostringstream& Get()
{
return ss;
}
};
int main()
{
int foo = 12;
bool bar = false;
std::string baz = "hello world";
MyLogger().Get() << foo << bar << baz << std::endl;
// less verbose to use a macro:
#define MY_LOG() MyLogger().Get()
MY_LOG() << baz << bar << foo << std::endl;
return 0;
}

I like to derive my logging class from std::ostream, so I get all of the stream goodness. The trick is to put all of your application-specific code in the associated streambuf class. Consider this working example. To modify it to meed your needs, simply rewrite CLogBuf::sync(), like so:
int sync() {
renderer->renderText(50, 50, color, "%s", str());
str("");
return false;
}
Example:
#include <iostream>
#include <sstream>
class CLogger : public std::ostream {
private:
class CLogBuf : public std::stringbuf {
private:
// or whatever you need for your application
std::string m_marker;
public:
CLogBuf(const std::string& marker) : m_marker(marker) { }
~CLogBuf() { pubsync(); }
int sync() { std::cout << m_marker << ": " << str(); str(""); return !std::cout; }
};
public:
// Other constructors could specify filename, etc
// just remember to pass whatever you need to CLogBuf
CLogger(const std::string& marker) : std::ostream(new CLogBuf(marker)) {}
~CLogger() { delete rdbuf(); }
};
int main()
{
CLogger hi("hello");
CLogger bye("goodbye");
hi << "hello, world" << std::endl;
hi << "Oops, forgot to flush.\n";
bye << "goodbye, cruel world\n" << std::flush;
bye << "Cough, cough.\n";
}

Related

Does the stream operator exist for class member functions?

I included the logger from boost. I'm pretty pleased how it works. Just for simplicity and the reason I don't want to use makros to often in my code, I wrap it in a class.
I now wonder if I could use the streaming operator << to write on a member function.
code
class LogWrapper{
...
//debug function
//info function
...
}
void main() {
LogWrapper log;
log.debug() << "some debug msg"; // does this exist?
log.info() << "some info msg";
}
output
[some_timestamp][debug] some debug msg
[some_timestamp][info] some info msg
Is this possible in a good practice, or is it entirely bad style?
It can be done easily like this:
#include <iostream>
class A {
public:
std::ostream &debug() const {
std::cerr << "[timestamp]" << "[DEBUG]";
return std::cerr;
}
};
int main()
{
A a;
a.debug() << "Test";
}
But the important question here is: Should we implement it in this way? In my opinion, NO!
Because you are thinking that the User of the class will print the logs like this:
int main()
{
A a;
a.debug() << "Test" << std::endl;
a.debug() << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
[timestamp][DEBUG]Test2
But what if User chooses this way:
int main()
{
A a;
auto &out = a.debug();
out << "Test" << std::endl;
out << "Test2" << std::endl;
}
Output:
[timestamp][DEBUG]Test
Test2
I would highly recommend not to return stream object. You should use member functions for this purpose.
#include <iostream>
class A {
public:
static void debug(const std::string &log) {
std::cerr << "[timestamp]" << "[DEBUG]" << log << std::endl;
}
};
int main()
{
A::debug("Test 1");
A::debug("Test 2");
}
Output:
[timestamp][DEBUG]Test 1
[timestamp][DEBUG]Test 2

setters function inside constructor c++

I'm trying to use a setter function inside of a constructor, which I've never done before. It's giving me the following error:
[Error] no match for call to '(Laptop) (const char [5], const char [3], int, int)'
well do i need to write the setter function too ? i mean outside the constructor ? i mean like this
void Laptop::setBrand(char a[])
{
brand=a;}
I think the error is in the second constructor, that takes four arguments, but I'm not able to find it.
Here is the code:
#include <iostream>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
using namespace std;
class Laptop{
private:
char brand[10];
char processor[10];
int ram;
int hardDrive;
public:
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
void setRam(int Ram);
void setHardDrive(int HDrive);
char *getBrand();
char *getProcessor();
int getRam();
int getHardDrive();
Laptop();
Laptop(char [],char [],int ,int );
};
Laptop::Laptop(){
cout<<"Default constructor called...\n";
strcpy(brand,"None");
strcpy(processor,"None);
ram=0;
hardDrive=0;
}
i think the error is in the constructor
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
{
cout<<"Parameterized constructor called...\n";
setBrand(Bra );
setProcessor(Pro );
setRam(Ram);
setHardDrive(HDrive);
}
char *Laptop::getBrand()
{
return brand;
}
char *Laptop::getProcessor()
{
return processor;
}
int Laptop::getRam()
{
return ram;
}
int Laptop::getHardDrive()
{
return hardDrive;
}
int main()
{
Laptop laptopObj1;
Laptop laptopobj1("Dell","i5",4,500);
cout<<"Brand :"<<laptopObj1.getBrand()<<"\n";
cout<<"Processor :"<<laptopObj1.getProcessor()<<"\n";
cout<<"Ram :"<<laptopObj1.getRam()<<"\n";
cout<<"HardDrive :"<<laptopObj1.getHardDrive()<<"\n";
cout<<"Brand :"<<laptopObj2.getBrand()<<"\n";
cout<<"Processor :"<<laptopObj2.getProcessor()<<"\n";
cout<<"Ram :"<<laptopObj2.getRam()<<"\n";
cout<<"HardDrive :"<<laptopObj2.getHardDrive()<<"\n";
}
You have alot of errors here..
Laptop laptopObj1,laptopObj2;
...
laptopObj2("Dell","i5", 4, 500);
You cant use the constructor twice. You used the constructor Laptop() in the first line for both of the object, and then tried to use the second constructor for laptopObj2.
You can change the second line to:
laptopObj2 = Laptop("Dell","i5", 4, 500);
Or even better to define it there:
Laptop laptopObj1;
....
Laptop laptopObj2("Dell","i5", 4, 500);
Another problem is inside your Laptop() constructor definition:
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
{
.....
setBrand(Bra []); // Remove the []
setProcessor(Pro []); // Remove the []
....
}
And one more problem: You have no definitions for some functions of the class:
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
void setRam(int Ram);
void setHardDrive(int HDrive);
void display();
EDIT:
One of the objects of c++ is std::string (#include <string>). You can use it instead of char str[]- just simpler way to declare strings in c++. For example, in your case:
/* Replace this: */
char brand[10];
char processor[10];
void setBrand(char Bra[]);
void setProcessor(char Pro[]);
char *getBrand();
char *getProcessor();
/* With this: */
string brand;
string processor;
void setBrand(const string &Bra);
void setProcessor(const string &Pro);
string getBrand();
string getProcessor();
You are passing two const char* as parameter, so you should change this :
Laptop::Laptop(char Bra[],char Pro[],int Ram,int HDrive)
to this:
Laptop::Laptop(const char* ,const char* ,int Ram,int HDrive)
You really should use std::string rather than char[].
On the question of constructors, there is no need to call setters, as the following code demonstrates. C++ has a shortcut for that capability. I have used std::string and fixed all typos.
#include <iostream>
#include <string>
using namespace std;
class Laptop
{
private:
string brand;
string processor;
int ram;
int hardDrive;
public:
void setBrand(string Bra);
void setProcessor(string Pro);
void setRam(int Ram);
void setHardDrive(int HDrive);
string getBrand();
string getProcessor();
int getRam();
int getHardDrive();
Laptop();
Laptop(string, string, int, int);
};
Laptop::Laptop()
: brand("None")
, processor("None")
, ram(0)
, hardDrive(0)
{
cout << "Default constructor called...\n";
}
Laptop::Laptop(string Bra, string Pro, int Ram, int HDrive)
: brand(Bra)
, processor(Pro)
, ram(Ram)
, hardDrive(HDrive)
{
cout << "Parameterized constructor called...\n";
}
string Laptop::getBrand()
{
return brand;
}
string Laptop::getProcessor()
{
return processor;
}
int Laptop::getRam()
{
return ram;
}
int Laptop::getHardDrive()
{
return hardDrive;
}
int main()
{
Laptop laptopObj1;
Laptop laptopObj2("Dell", "i5", 4, 500);
cout << "Brand :" << laptopObj1.getBrand() << "\n";
cout << "Processor :" << laptopObj1.getProcessor() << "\n";
cout << "Ram :" << laptopObj1.getRam() << "\n";
cout << "HardDrive :" << laptopObj1.getHardDrive() << "\n";
cout << "Brand :" << laptopObj2.getBrand() << "\n";
cout << "Processor :" << laptopObj2.getProcessor() << "\n";
cout << "Ram :" << laptopObj2.getRam() << "\n";
cout << "HardDrive :" << laptopObj2.getHardDrive() << "\n";
}
Mike

Call method by string and pass arguments

i search for a way to call a method by its string name.
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << run << std::endl;
}
void method2(int run){
std::cout << run << std::endl;
}
};
int main(){
myClass mc;
std::string call;
call = "method1";
mc.call(1);
call = "method2";
mc.call(2);
}
But the result, is
‘class Myclass’ has no member named ‘call’
I need response "1" and "2";
EDIT :: Very thank's for your help, i get the next solution (i don't know is good for all cases );
#include <iostream>
#include <string>
class myClass{
public:
void method1(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void method2(int run){
std::cout << "Loaded method => " << run << std::endl;
}
void _loadMethods(int method, int params){
switch(method) {
case 1:
method1(params);
break;
case 2:
method2(params);
break;
default:
break;
}
}
};
int main(){
myClass mc;
std::string method;
method = "method2";
if(method == "method1"){
mc._loadMethods(1, 1);
}
if(method == "method2"){
mc._loadMethods(2, 2);
}
}
Thank's
This is not possible in "raw" C++. But... What you are trying to achieve is some kind of Reflection or Class meta-type information.
You can look at this project: http://www.axelmenzel.de/projects/coding/rttr , use Qt: http://doc.qt.io/qt-5/qmetatype.html#details or google for C++ reflection.

How can I use the boost visitor concept with a class containing state variables?

I'm attempting to use boost::static_visitor to implement actions on a boost::variant type that affect the state of some variable. My approach was to contain all of the state variables in my command visitor class, but it seems this is not possible.
Here is my code example:
#include <string>
#include <sstream>
#include <vector>
#include <boost/variant.hpp>
#include <boost/foreach.hpp>
struct TypeA
{
int varA;
int varB;
};
struct TypeB
{
std::string varA;
std::string varB;
};
typedef boost::variant<TypeA, TypeB> MyVariantType;
class MyCommandVisitor : public boost::static_visitor<>
{
public:
//These are just examples, the actions only need to be able to touch
// internal variables.
void operator()(TypeA & t) const
{
m_runningSum += t.varA;
m_outStream << "TYPEA ACTION: " << t.varB << std::endl;
}
void operator(TypeB & t) const
{
m_charCount += t.varA.size();
m_outStream << t.varB << " ACTION " << t.varA << std::endl;
}
std::string emitWork(std::vector<MyVariantType> listOfVariants)
{
m_outStream.clear();
m_runningSum = 0;
m_charCount = 0;
BOOST_FOREACH(MyVariantType & v, listOfVariants)
{
boost::apply_visitor(*this, v);
}
return m_outStream.str();
}
protected:
int m_runningSum;
int m_charCount;
std::stringstream outStream;
}; //End class MyCommandVisitor
int main(int argc, char **argv)
{
TypeA ta;
ta.varA = 1;
ta.varB = 2;
TypeB tb;
tb.varA = "String1";
tb.varB = "String2";
std::vector<MyVariantType> listOfWork;
listOfWork.push_back(ta);
listOfWork.push_back(tb);
MyCommandVisitor myCV;
std::string result = myCV.emitWork(listOfWork);
std::cout << "Result:\n" << result << std::endl << std::endl;
return 0;
}
I hope this snippet gets across the gist of what I'm trying to accomplish. It won't compile, however, giving the [paraphrased] error:
error: no operator "<<" matches these operands
operand types are: const std::stringstream << const char [N]
m_outStream << "TYPE A ACTION: " << t.varB << std::endl;
^
I'm assuming this error is due to the const modifier that must be placed on the end of the operator() function prototype which makes the compiler believe that member variables cannot be modified by the function.
My question is thus:
What is the proper way to accomplish the visitor pattern (using boost::variant) with variables that must maintain state between visits?
There were a couple of typos, but I made a few mods and it works now. Essentially your static_visitor class is mutating itself on each visit, so the operator() methods can't be const.
#include <string>
#include <sstream>
#include <vector>
#include <boost/variant.hpp>
#include <boost/foreach.hpp>
#include <iostream>
struct TypeA
{
int varA;
int varB;
};
struct TypeB
{
std::string varA;
std::string varB;
};
typedef boost::variant<TypeA, TypeB> MyVariantType;
class MyCommandVisitor : public boost::static_visitor<>
{
public:
//These are just examples, the actions only need to be able to touch
// internal variables.
void operator()(TypeA & t)
{
m_runningSum += t.varA;
m_outStream << "TYPEA ACTION: " << t.varB << std::endl;
}
void operator()(TypeB & t)
{
m_charCount += t.varA.size();
m_outStream << t.varB << " ACTION " << t.varA << std::endl;
}
std::string emitWork(std::vector<MyVariantType> listOfVariants)
{
m_outStream.clear();
m_runningSum = 0;
m_charCount = 0;
BOOST_FOREACH(MyVariantType & v, listOfVariants)
{
boost::apply_visitor(*this, v);
}
return m_outStream.str();
}
protected:
int m_runningSum;
int m_charCount;
std::stringstream m_outStream;
}; //End class MyCommandVisitor
int main(int argc, char **argv)
{
TypeA ta;
ta.varA = 1;
ta.varB = 2;
TypeB tb;
tb.varA = "String1";
tb.varB = "String2";
std::vector<MyVariantType> listOfWork;
listOfWork.push_back(ta);
listOfWork.push_back(tb);
MyCommandVisitor myCV;
std::string result = myCV.emitWork(listOfWork);
std::cout << "Result:\n" << result << std::endl << std::endl;
return 0;
}
running on http://www.compileonline.com/compile_cpp11_online.php gives:
Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
Result:
TYPEA ACTION: 2
String2 ACTION String1
I'd personally favour making the functor const. Instead, I like to bind the functor arguments to references:
static std::string emitWork(std::vector<MyVariantType> const listOfVariants) {
int sum = 0, charCount = 0;
std::stringstream os;
BOOST_FOREACH(MyVariantType const& v, listOfVariants) {
boost::apply_visitor(
boost::bind(MyCommandVisitor(), _1, boost::ref(os), boost::ref(sum), boost::ref(charCount)),
v);
}
return os.str();
}
Note that
emitWork can now be static, reentrant etc.
the operator() can now be const
The rest of the visitor would look like this:
struct MyCommandVisitor : boost::static_visitor<> {
void operator()(TypeA const& t, std::stringstream& os, int& sum, int& /*charCount*/) const {
sum += t.varA;
os << "TYPEA ACTION: " << t.varB << std::endl;
}
void operator()(TypeB const& t, std::stringstream& os, int& /*sum*/, int& charCount) const {
charCount += t.varA.size();
os << t.varB << " ACTION " << t.varA << std::endl;
}
};
See it Live On Coliru

Best way to add a "prompt" message to std::cout

I'm searching the best way to add a custom, initial message to all the messages that std::cout (or std::cerr) prints to console/file output.
For example, if I setup that this custom prompt message will be the string "[Log]", then a classic
std::cerr << "This is a log message" << std::endl;
will be printed in this way:
> [Log] This is a log message
Clearly I can obtain this behavior using
std::string PROMPT_MSG = "[Log]";
std::cerr << PROMPT_MSG << "This is a log message" << std::endl;
but I'd like a less invasive way.
Thanks in advance
You could write your own class:
#include <iostream>
#include <string>
class MyLogger
{
std::ostream & out;
std::string const msg;
public:
MyLogger(std::ostream & o, std::string s)
: out(o)
, msg(std::move(s))
{ }
template <typename T>
std::ostream & operator<<(T const & x)
{
return out << msg << x;
}
};
MyLogger MyErr(std::cerr, "[LOG] ");
Usage:
MyErr << "Hello" << std::endl;
As Joachim Pileborg suggested you can use a logging framework. YOu can use an existing one or start with your own that will contain just one class:
class MyLogger{}
template <typename T>
MyLogger& operator << (MyLogger& logger, const T& logStuff)
{
std::cerr << PROMPT_MSG << logStuff << std::endl;
return logger;
}
then define a global variable of class MyLogger:
MyLogger mylogger;
then when you want to write a log record, write:
mylogger << "This is a log message";
overloaded operator << of class MyLogger will do what you want;
I had the same problem in a recent project. I solved it with this little class:
class DebugOut
{
public:
static const int COLUMN_WIDTH = 15;
DebugOut(const std::wstring &type)
{
std::wcout << type;
for(int i=type.length();i<COLUMN_WIDTH;i++)
std::wcout << " ";
std::wcout << ": ";
}
~DebugOut()
{
std::wcout << std::endl;
}
template <typename T>
friend DebugOut& operator<<(DebugOut& out,T i)
{
std::wcout << i;
return out;
}
};
Sample usage: DebugOut(L"Log") << "Something";
I guess you could just define a function log and a function error, and then just call them when you want to print a log or error method. That way you don't have to add the PROMPT_MSG every time.