I am trying to implement a class in C++ to imitate the syntax of the print and write statements from FORTRAN.
In order to achieve this, I implemented a class fooprint
and overloaded fooprint::operator,
(comma operator). Since this class should print to the standard output or to a file, I also defined two macros: print
(for stdout) and write
(to operate on files).
I get compilation errors when trying to use write(data) a;
(see below for error log). How can I get a working write
statement with the above properties?
This is the code (Live Demo):
#include <iostream>
#include <fstream>
class fooprint
{
private:
std::ostream *os;
public:
fooprint(std::ostream &out = std::cout) : os(&out) {}
~fooprint() { *os << std::endl;}
template<class T>
fooprint &operator, (const T output)
{
*os << output << ' ';
return *this;
}
};
#define print fooprint(), // last comma calls `fooprint::operator,`
#define write(out) fooprint(out),
int main()
{
double a = 2.0;
print "Hello", "World!"; // OK
print "value of a =", a; // OK
print a; // OK
std::ofstream data("tmp.txt");
write(data) "writing to tmp"; // compiles with icpc; it doesn't with g++
write(data) a; // this won't compile
data.close();
return 0;
}
And the compilation message:
g++ -Wall -std=c++11 -o print print.cc
error: conflicting declaration ‘fooprint data’
#define write(out) fooprint(out),
^
note: in expansion of macro ‘write’
write(data) a;
^
error: ‘data’ has a previous declaration as ‘std::ofstream data’
error: conflicting declaration ‘fooprint a’
write(data) a;
^
error: ‘a’ has a previous declaration as ‘double a’
icpc -Wall -std=c++11 -o print print.cc
error: "data" has already been declared in the current scope
write(data) a;
error: "a" has already been declared in the current scope
write(data) a;
fooprint(out)
is not the creation of a temporary but rather the declaration of a variable of typefooprint
with the name provided as the argument to the macro. In order to not make this a declaration, and instead an expression, two quick changes you can make are surrounding it in parenthesis(fooprint(out))
or using brace-initialization (C++11) (fooprint{out}
).