Handle unknown number of undefined objects for logging - c++

Trying to reproduce something that in C# you would do something like this:
string FormatString(params object[] args) {
return string.Format(CultureInfo.InvariantCulture, args);
}
And in Obj-c it would look like this:
#include <stdarg.h>
void logObjects(id firstObject, ...) {
va_list args;
va_start(args, firstObject);
id obj;
for (obj = firstObject; obj != nil; obj = va_arg(args, id))
NSLog(#"%#", obj);
va_end(args);
}
logObjects(#"foo", [NSNumber numberWithInt:4], #"bar", nil);
I'm familiar with variable parameter length but not too sure how to store the args and then send them to std::cout. Is this even possible?
Notice! I want to send any kind of object which can handle the << operator. Just look at this function as a substitute for:
std::cout << "test" << someObject << int << someOtherObject;
I am using boost and would like to keep it platform independent. This function will be part of a logging class in a shared lib.

It doesn't work in C# too because the format string is missing anyway concept is clear. In C you can do something like this (as seen in dbgprint, if you have variadic macro feature)
#define printfex(...) printf(__VA_ARGS__)
If you're so lucky to use C++11 you can write this prototype:
template<class... T>
void printfex(const std::string& format, T... args);

You cannot use run-time variadic parameters in C++- that's a basic fact. You must use the same technique that the C++ streams do - operator overloading. Fortunately, C++ already contains such functionality.
void f(const std::stringstream& str) {
std::cout << str;
}
int main() {
int i = 5;
f(std::stringstream() << "i is equal to " << 5);
}

Sorry but I don't know very much about C#. Do you want to send a list of parameters to std::cout? That's not complicated:
void formatString (const std::vector<std::string>& args)
{
for (int i=0; i<args.size (); ++i)
{
std::cout << args[i];
}
std::cout << std::endl;
}
And you can store the elements in the following way:
std::vector test (2);
test[0] = "one";
test[1] = "two";
formatString (test);
UPDATE
Copy & Paste this into a .cpp file and compile it.
You have to implement the IPrintable interface for every class you want to log. Maybe is not the most efficient solution but it works.
#include <iostream>
#include <string>
#include <vector>
class IPrintable
{
public:
virtual ~IPrintable () { }
virtual std::string toString () const = 0;
};
class ClassA : public IPrintable
{
public:
std::string toString () const
{
std::string s = "Class A to string";
return s;
}
};
class ClassB : public IPrintable
{
public:
std::string toString () const
{
std::string s = "Class B to string";
return s;
}
};
void print (const std::vector<IPrintable*> args)
{
for (int i=0; i<args.size (); ++i)
{
std::cout << args[i]->toString () << std::endl;
}
}
int main (int argc, char* argv[])
{
ClassA a;
ClassB b;
std::vector<IPrintable*> v (2);
v[0] = &a;
v[1] = &b;
print (v);
return 0;
}

Related

Attach callback function without `std::function` [duplicate]

I want to be able to call functions based on the data I read from file.
So for each item type, I want to call the desired reader method.
I wrote this code, but it does not compile where I want to add function pointers to the map. What is wrong?
#include <vector>
#include <map>
#include <iostream>
class reader
{
std::map< std::string, void(*)()> functionCallMap; // function pointer
void readA(){ std::cout << "reading A\n";};
void readB(){ std::cout << "reading B\n";};;
public:
reader()
{
*functionCallMap["A"] = &reader::readA;*
*functionCallMap["B"] = &reader::readB;*
}
void read()
{
auto (*f) = functionCallMap["A"];
(*f)();
}
};
I am filling the map at Constructor.
You can use std::function with a lambda or std::bind :
class reader
{
std::map<std::string, std::function<void()>> functionCallMap;
void readA() { std::cout << "reading A\n"; };
void readB() { std::cout << "reading B\n"; };
public:
reader()
{
functionCallMap["A"] = [this]() { readA(); };
functionCallMap["B"] = std::bind(&reader::readB, this);
}
void read()
{
functionCallMap["A"]();
functionCallMap["B"]();
}
};
You need to use pointers to member functions, like this:
class reader
{
using FuncPtr = void(reader::*)(); // function pointer
std::map< std::string, FuncPtr> functionCallMap;
void readA(){ std::cout << "reading A\n"; }
void readB(){ std::cout << "reading B\n"; }
public:
reader()
{
functionCallMap["A"] = &reader::readA;
functionCallMap["B"] = &reader::readB;
}
void read()
{
auto f = functionCallMap["A"];
(this->*f)();
}
};
int main()
{
reader r;
r.read();
}
There are two answers so far, this and this.
The obvious difference is that one uses std::function and other uses function pointers. This is not the important difference!!
The key point is that the member functions are non-static member functions. So, they are not of type void().
They are of type void(reader::*)(). Thus, they can be only called if an object of type is reader is given; one can understand this somewhat as a hidden parameter.
The first answer just fixes the problem by specifying the correct type. This can be done using function pointers (as presented) or using std::function (The latter is much more expensive!).
The second answer fixes the problem by binding the function pointer to the particular instance of the class. After binding, the type is then indeed void(). This cannot be done using raw function pointers (because they can only point to a function and not an object/function pair!).
I ended up with this solution. It does the job, but I have some doubts over its aesthetics. Anyway, to sum up, I ended up with this code:
#include <map>
#include <iostream>
#include <functional>
class reader
{
std::map< std::string, std::function<void(std::string tableName)>> functionCallMap; // function pointer
void readA(const std::string tableName){ std::cout << "reading:" << tableName<< "\n"; }
void readB(const std::string tableName){ std::cout << "reading:" << tableName <<"\n"; }
public:
reader()
{
functionCallMap["A"] = std::bind(&reader::readA, this, std::placeholders::_1);
functionCallMap["B"] = std::bind(&reader::readA, this, std::placeholders::_1);
}
void read()
{
const std::string table_name = "A";
functionCallMap[table_name](table_name);
}
};
int main()
{
reader r;
r.read();
}
I pass the table name to the reader, it is nicely done with the bind and placeholder.

How to store methods as function pointers in a map container?

I want to be able to call functions based on the data I read from file.
So for each item type, I want to call the desired reader method.
I wrote this code, but it does not compile where I want to add function pointers to the map. What is wrong?
#include <vector>
#include <map>
#include <iostream>
class reader
{
std::map< std::string, void(*)()> functionCallMap; // function pointer
void readA(){ std::cout << "reading A\n";};
void readB(){ std::cout << "reading B\n";};;
public:
reader()
{
*functionCallMap["A"] = &reader::readA;*
*functionCallMap["B"] = &reader::readB;*
}
void read()
{
auto (*f) = functionCallMap["A"];
(*f)();
}
};
I am filling the map at Constructor.
You can use std::function with a lambda or std::bind :
class reader
{
std::map<std::string, std::function<void()>> functionCallMap;
void readA() { std::cout << "reading A\n"; };
void readB() { std::cout << "reading B\n"; };
public:
reader()
{
functionCallMap["A"] = [this]() { readA(); };
functionCallMap["B"] = std::bind(&reader::readB, this);
}
void read()
{
functionCallMap["A"]();
functionCallMap["B"]();
}
};
You need to use pointers to member functions, like this:
class reader
{
using FuncPtr = void(reader::*)(); // function pointer
std::map< std::string, FuncPtr> functionCallMap;
void readA(){ std::cout << "reading A\n"; }
void readB(){ std::cout << "reading B\n"; }
public:
reader()
{
functionCallMap["A"] = &reader::readA;
functionCallMap["B"] = &reader::readB;
}
void read()
{
auto f = functionCallMap["A"];
(this->*f)();
}
};
int main()
{
reader r;
r.read();
}
There are two answers so far, this and this.
The obvious difference is that one uses std::function and other uses function pointers. This is not the important difference!!
The key point is that the member functions are non-static member functions. So, they are not of type void().
They are of type void(reader::*)(). Thus, they can be only called if an object of type is reader is given; one can understand this somewhat as a hidden parameter.
The first answer just fixes the problem by specifying the correct type. This can be done using function pointers (as presented) or using std::function (The latter is much more expensive!).
The second answer fixes the problem by binding the function pointer to the particular instance of the class. After binding, the type is then indeed void(). This cannot be done using raw function pointers (because they can only point to a function and not an object/function pair!).
I ended up with this solution. It does the job, but I have some doubts over its aesthetics. Anyway, to sum up, I ended up with this code:
#include <map>
#include <iostream>
#include <functional>
class reader
{
std::map< std::string, std::function<void(std::string tableName)>> functionCallMap; // function pointer
void readA(const std::string tableName){ std::cout << "reading:" << tableName<< "\n"; }
void readB(const std::string tableName){ std::cout << "reading:" << tableName <<"\n"; }
public:
reader()
{
functionCallMap["A"] = std::bind(&reader::readA, this, std::placeholders::_1);
functionCallMap["B"] = std::bind(&reader::readA, this, std::placeholders::_1);
}
void read()
{
const std::string table_name = "A";
functionCallMap[table_name](table_name);
}
};
int main()
{
reader r;
r.read();
}
I pass the table name to the reader, it is nicely done with the bind and placeholder.

How can I have an object with differing parameter types while it's also in a vector?

I currently wish to have a vector of objects where each object has differing properties.
Intended outcome:
//v is a vector
v.push_back(ttSaveObj(5, "int example"));
v.push_back(ttSaveObj("Hello, world!", "string example"));
std::cout << v[0].data << " " << v[0].variableName << std::endl; //Intended Output: 5 int example
std::cout << v[1].data << " " << v[1].variableName << std::endl; //Intended Output: Hello, world! string example
Based on this answer I tried having a constructor function for the class with <void*> in the template, but this seems just create a pointer to void (as I partially expected).
ttSaveObj.hpp:
template <typename T>
class ttSaveObj {
public:
ttSaveObj(T pVar, std::string pName) {
data = pVar;
variableName = pName;
};
~ttSaveObj() {};
std::string variableName;
T data;
};
ttGameObj.hpp:
#include "ttSaveObj.hpp"
class ttGameObj {
public:
ttGameObj();
~ttGameObj();
std::vector<ttSaveObj<void*>> data;
};
ttGameObj.cpp:
#include "ttGameObj.hpp"
ttGameObj::ttGameObj() {
int asdf = 5;
int * test = &asdf;
data.push_back(ttSaveObj<void*>(test, "X"));
std::cout << &data[0].data << " " << data[0].variableName << std::endl; //Output: 0x15fb770 X
}
Anything that will help me get closer to my intended outcome is appreciated, thanks!
The objects you put in the vector seem to have two data members: variableName, which is of fixed std::string type, and a data field, which is of varying type.
You may consider using C++17's std::variant (or Boost's variant implementation) for the data field. For example, if you plan to support the types int, float and std::string for your data, you can use a std::variant<int, float, std::string>.
There's also std::any, if you want to store instances of any type (that satisfy the requirements described in the std::any documentation).
In modern C++ I'd suggest to avoid the C-style void*, and use it only if strictly necessary (e.g. if you are at some legacy C API boundary): there are safer, more robust and higher-level alternatives to it.
Another option (if it makes better sense for your design) is to define a base class (interface) for the objects you want to put in your vector, and define custom classes that implement this interface. In this case, I suggest using smart pointers (like e.g. std::unique_ptr or std::shared_ptr) to manage those objects in a simple and safe way (I saw another answer here that used raw pointers, requiring explicit new/delete - actually in that code there were news but no delete, with consequent resource leaks).
E.g.:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;
// Interface for an element to be inserted in the vector
class IElement
{
public:
IElement() {}
virtual ~IElement() {}
virtual string ToString() = 0;
// Other virtual methods ...
};
class IntElement : public IElement
{
public:
explicit IntElement(int n) : _n{ n } {}
virtual string ToString() override
{
return to_string(_n);
}
private:
int _n;
};
class StringElement : public IElement
{
public:
explicit StringElement(const string& s) : _s{ s } {}
virtual string ToString() override
{
return _s;
}
private:
string _s;
};
int main()
{
vector<shared_ptr<IElement>> elements;
elements.push_back(make_shared<IntElement>(10));
elements.push_back(make_shared<IntElement>(20));
elements.push_back(make_shared<StringElement>("Hello"));
elements.push_back(make_shared<StringElement>("World"));
for (const auto& e : elements)
{
cout << e->ToString() << '\n';
}
}
Output:
10
20
Hello
World
If you are using C++11 then you can use the tuple class in the standard library. You could make this object like so:
auto v = std::make_tuple(ttSaveObj(5, "int example"), ttSaveObj("Hello, world!", "string example"))
std::cout << std::get<0>(v).data << " " << std::get<0>(v).variableName << std::endl;
There is a drawback though that the index for access is a template argument and must therefore be known at compile time, meaning that you can't loop through the elements. Also the types of the elements in the tuple must be known at compile time.
If I understood your goals correctly, Java-like approach could take place, but you should wrap the vector to never forget the clean up.
// Example program
#include <iostream>
#include <string>
#include <vector>
#include <string.h>
#include <memory>
using std::vector;
class Object
{
public:
explicit Object() {}
virtual ~Object() {}
virtual const char* toString() const = 0;
};
class StringObject : public Object
{
public:
explicit StringObject(const char* string) : Object()
{
if(string != 0)
{
m_value = new char[strlen(string) + 1];
strcpy(((char*)m_value), string);
} else
{
m_value = new char[1];
m_value[0] = 0;
}
}
virtual ~StringObject()
{
delete m_value;
}
virtual const char* toString() const
{
return (const char*)m_value;
}
private:
char* m_value;
};
class IntObject : public Object
{
public:
explicit IntObject(int val) : Object()
{
m_value = val;
}
virtual ~IntObject()
{
}
virtual const char* toString() const
{
return std::to_string(m_value).c_str();
}
private:
int m_value;
};
int main()
{
auto vec = vector<std::unique_ptr<Object>>();
vec.push_back(std::make_unique<IntObject>(9));
vec.push_back(std::make_unique<IntObject>(11));
vec.push_back(std::make_unique<StringObject>("hello"));
vec.push_back(std::make_unique<StringObject>("world"));
for(const auto& v : vec)
{
std::cout << v.get()->toString() << " ";
}
}
Output, as expected, "9 11 hello world".

how pass an array as parameter, and the array is defined in the parameters in c++

I am converting a c# written program into c++ code. I have a c# function declaration like:
// c# function declaration
int DerivationFunc(int id, params BasicFeature[] args);
So I convert it to c++
// c++ function declaration
int DerivationFunc(int id, BasicFeature* args, int argsNum); // argsNum denotes the size of the array
Now I have problems when calling the functions. In c#, I can call the function with the array definition in the parameters:
// c# function calling
DerivationFunc(16, new BasicFeature[] {query, keyword});
So how can I do this in C++?
// c++ function calling
DerivationFunc(16, /*something like BasicFeature[] {query, keyword} but with the right syntax*/, 2);
You could rewrite the function to take std::initializer_list:
#include <initializer_list>
#include <iostream>
struct BasicFeature {
} query, keyword;
int DerivationFunc(int id, std::initializer_list<BasicFeature> args)
{
std::cout << args.size() << " element(s) were passed.\n";
return id;
}
int main()
{
DerivationFunc(42, { query, keyword });
}
If you are not allowed to use std::initializer_list, I could suggest a little ugly hack:
#include <vector>
#include <iostream>
enum BasicFeature {
query,
keyword
};
template<typename T>
class init_list
{
public:
init_list &operator<<( typename T::value_type value )
{
m_list.push_back(value);
}
operator const T() const { return m_list; }
private:
T m_list;
};
void DeriviationFunc( int id, const std::vector<BasicFeature> &args )
{
std::cout << id << std::endl;
std::cout << args.size() << std::endl;
std::cout << args[0] << std::endl;
}
int main()
{
DeriviationFunc(16, init_list<std::vector<BasicFeature> >() << query << keyword);
return 0;
}

C++ callback using class member

I know this has been asked so many times, and because of that it's difficult to dig through the cruft and find a simple example of what works.
I've got this, it's simple and it works for MyClass...
#include <iostream>
using std::cout;
using std::endl;
class MyClass
{
public:
MyClass();
static void Callback(MyClass* instance, int x);
private:
int private_x;
};
class EventHandler
{
public:
void addHandler(MyClass* owner)
{
cout << "Handler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner,1);
}
};
EventHandler* handler;
MyClass::MyClass()
{
private_x = 5;
handler->addHandler(this);
}
void MyClass::Callback(MyClass* instance, int x)
{
cout << x + instance->private_x << endl;
}
int main(int argc, char** argv)
{
handler = new EventHandler();
MyClass* myClass = new MyClass();
}
class YourClass
{
public:
YourClass();
static void Callback(YourClass* instance, int x);
};
How can that be rewritten so EventHandler::addHandler() will work with both MyClass and YourClass. I'm sorry but it's just the way my brain works, I need to see a simple example of what works before I can comprehend why/how it works. If you've got a favorite way to make this work now's the time to show it off, please markup that code and post it back.
[edit]
It was answered but the answer was deleted before I could give the checkmark.
The answer in my case was a templated function. Changed addHandler to this...
class EventHandler
{
public:
template<typename T>
void addHandler(T* owner)
{
cout << "Handler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner,1);
}
};
Instead of having static methods and passing around a pointer to the class instance, you could use functionality in the new C++11 standard: std::function and std::bind:
#include <functional>
class EventHandler
{
public:
void addHandler(std::function<void(int)> callback)
{
cout << "Handler added..." << endl;
// Let's pretend an event just occured
callback(1);
}
};
The addHandler method now accepts a std::function argument, and this "function object" have no return value and takes an integer as argument.
To bind it to a specific function, you use std::bind:
class MyClass
{
public:
MyClass();
// Note: No longer marked `static`, and only takes the actual argument
void Callback(int x);
private:
int private_x;
};
MyClass::MyClass()
{
using namespace std::placeholders; // for `_1`
private_x = 5;
handler->addHandler(std::bind(&MyClass::Callback, this, _1));
}
void MyClass::Callback(int x)
{
// No longer needs an explicit `instance` argument,
// as `this` is set up properly
cout << x + private_x << endl;
}
You need to use std::bind when adding the handler, as you explicitly needs to specify the otherwise implicit this pointer as an argument. If you have a free-standing function, you don't have to use std::bind:
void freeStandingCallback(int x)
{
// ...
}
int main()
{
// ...
handler->addHandler(freeStandingCallback);
}
Having the event handler use std::function objects, also makes it possible to use the new C++11 lambda functions:
handler->addHandler([](int x) { std::cout << "x is " << x << '\n'; });
Here's a concise version that works with class method callbacks and with regular function callbacks. In this example, to show how parameters are handled, the callback function takes two parameters: bool and int.
class Caller {
template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
{
using namespace std::placeholders;
callbacks_.emplace_back(std::bind(mf, object, _1, _2));
}
void addCallback(void(* const fun)(bool,int))
{
callbacks_.emplace_back(fun);
}
void callCallbacks(bool firstval, int secondval)
{
for (const auto& cb : callbacks_)
cb(firstval, secondval);
}
private:
std::vector<std::function<void(bool,int)>> callbacks_;
}
class Callee {
void MyFunction(bool,int);
}
//then, somewhere in Callee, to add the callback, given a pointer to Caller `ptr`
ptr->addCallback(this, &Callee::MyFunction);
//or to add a call back to a regular function
ptr->addCallback(&MyRegularFunction);
This restricts the C++11-specific code to the addCallback method and private data in class Caller. To me, at least, this minimizes the chance of making mistakes when implementing it.
Note that with C++20's bind_front you can simplify add_callback for class member functions to:
template<class T> void addCallback(T* const object, void(T::* const mf)(bool,int))
{
callbacks_.emplace_back(std::bind_front(mf, object));
}
What you want to do is to make an interface which handles this code and all your classes implement the interface.
class IEventListener{
public:
void OnEvent(int x) = 0; // renamed Callback to OnEvent removed the instance, you can add it back if you want.
};
class MyClass :public IEventListener
{
...
void OnEvent(int x); //typically such a function is NOT static. This wont work if it is static.
};
class YourClass :public IEventListener
{
Note that for this to work the "Callback" function is non static which i believe is an improvement. If you want it to be static, you need to do it as JaredC suggests with templates.
A complete working example from the code above.... for C++11:
#include <stdlib.h>
#include <stdio.h>
#include <functional>
#if __cplusplus <= 199711L
#error This file needs at least a C++11 compliant compiler, try using:
#error $ g++ -std=c++11 ..
#endif
using namespace std;
class EventHandler {
public:
void addHandler(std::function<void(int)> callback) {
printf("\nHandler added...");
// Let's pretend an event just occured
callback(1);
}
};
class MyClass
{
public:
MyClass(int);
// Note: No longer marked `static`, and only takes the actual argument
void Callback(int x);
private:
EventHandler *pHandler;
int private_x;
};
MyClass::MyClass(int value) {
using namespace std::placeholders; // for `_1`
pHandler = new EventHandler();
private_x = value;
pHandler->addHandler(std::bind(&MyClass::Callback, this, _1));
}
void MyClass::Callback(int x) {
// No longer needs an explicit `instance` argument,
// as `this` is set up properly
printf("\nResult:%d\n\n", (x+private_x));
}
// Main method
int main(int argc, char const *argv[]) {
printf("\nCompiler:%ld\n", __cplusplus);
new MyClass(5);
return 0;
}
// where $1 is your .cpp file name... this is the command used:
// g++ -std=c++11 -Wall -o $1 $1.cpp
// chmod 700 $1
// ./$1
Output should be:
Compiler:201103
Handler added...
Result:6
MyClass and YourClass could both be derived from SomeonesClass which has an abstract (virtual) Callback method. Your addHandler would accept objects of type SomeonesClass and MyClass and YourClass can override Callback to provide their specific implementation of callback behavior.
If you have callbacks with different parameters you can use templates as follows:
// compile with: g++ -std=c++11 myTemplatedCPPcallbacks.cpp -o myTemplatedCPPcallbacksApp
#include <functional> // c++11
#include <iostream> // due to: cout
using std::cout;
using std::endl;
class MyClass
{
public:
MyClass();
static void Callback(MyClass* instance, int x);
private:
int private_x;
};
class OtherClass
{
public:
OtherClass();
static void Callback(OtherClass* instance, std::string str);
private:
std::string private_str;
};
class EventHandler
{
public:
template<typename T, class T2>
void addHandler(T* owner, T2 arg2)
{
cout << "\nHandler added..." << endl;
//Let's pretend an event just occured
owner->Callback(owner, arg2);
}
};
MyClass::MyClass()
{
EventHandler* handler;
private_x = 4;
handler->addHandler(this, private_x);
}
OtherClass::OtherClass()
{
EventHandler* handler;
private_str = "moh ";
handler->addHandler(this, private_str );
}
void MyClass::Callback(MyClass* instance, int x)
{
cout << " MyClass::Callback(MyClass* instance, int x) ==> "
<< 6 + x + instance->private_x << endl;
}
void OtherClass::Callback(OtherClass* instance, std::string private_str)
{
cout << " OtherClass::Callback(OtherClass* instance, std::string private_str) ==> "
<< " Hello " << instance->private_str << endl;
}
int main(int argc, char** argv)
{
EventHandler* handler;
handler = new EventHandler();
MyClass* myClass = new MyClass();
OtherClass* myOtherClass = new OtherClass();
}