I'm trying to replace a #define function like the following:
#define DEBUG(x) do { std::cout << x << std::endl; } while(0)
with a more RAII type error tracking object. This tracking object currently resembles this (*updated to include "intro" for clarity; and included stack dump logic from Ahmed AEK):
class tracker() {
public:
tracker(std::string s) : intro(s) {}
~tracker() {
if( this->stack.empty()) return;
// dump_the_stack
std::cout << "Messages from: " << intro << std::endl;
for (const auto& item: stack) {
std::cout << " * " << item;
}
std::cout << std::endl;
// throw (abort)
}
void add( const std::string& message ) {
stack.push_back( message );
}
private:
std::string intro;
std::vector<const std::string> stack;
};
I would like to use this while keeping the existing #define syntax. For instance, I would like to have a method that allows the class user to maintain a syntax resembling one of these:
tracker.add( "value exceeded: " << value );
or even:
tracker << "value exceeded: " << value << std::endl;
Ideally, I believe the solution I want would look like:
tracker::add( ostringstream os ) {
stack.push_back( os.str() + std::endl );
}
But it appears that there's no implicit conversion to ostringstream for the first case, and there's no way to determine the terminal << in an operator<<() case. Is there a simple solution here that I'm overlooking?
EDIT: for clarification below, and added "intro" to sample class above:
My ideal scenario is being able to use the syntax in either of these two test cases:
Case 1 (preferred):
int main()
{
tracker t("test case 1");
int trace = 0;
t.add("hello world 1!" << " trace: " << ++trace);
t.add("hello world 2!" << " trace: " << ++trace);
return 0;
}
Case 2 (acceptable):
int main()
{
tracker t("test case 1");
int trace = 0;
t << "hello world 1!" << " trace: " << ++trace;
t << "hello world 2!" << " trace: " << ++trace;
return 0;
}
The resultant output should look like:
Messages from: test case 1
* hello world 1! trace: 1
* hello world 2! trace: 2
Thanks to everyone who responded. Here is what I have ended up with. Though I would prefer to use the function-like interface to be more consistent with existing code, this does work well and addresses my immediate needs. The biggest nuisance is requiring an end-token for terminating the message.
Here's a live example, maybe...