VC6 and template error - c++

I am overloading operator << to implement a stream like interface for a class:
template<typename T>
CAudit& operator << ( const T& data ) {
audittext << data;
return *this;
}
CAudit& operator << ( LPCSTR data ) {
audittext << data;
return *this;
}
The template version fails to compile with "fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1794)". Non-template functions all compile correctly.
Is this due to VC6s deficiencies when handling templates and is there a way around this?
Thanks,
Patrick
EDIT :
the full class is:
class CAudit
{
public:
/* TODO_DEBUG : doesn't build!
template<typename T>
CAudit& operator << ( const T& data ) {
audittext << data;
return *this;
}*/
~CAudit() { write(); }//If anything available to audit write it here
CAudit& operator << ( LPCSTR data ) {
audittext << data;
return *this;
}
//overload the << operator to allow function ptrs on rhs, allows "audit << data << CAudit::write;"
CAudit& operator << (CAudit & (*func)(CAudit &))
{
return func(*this);
}
void write() {
}
//write() is a manipulator type func, "audit << data << CAudit::write;" will call this function
static CAudit& write(CAudit& audit) {
audit.write();
return audit;
}
private:
std::stringstream audittext;
};
The problem occurs with the function overload of operator << which is used to allow write() to be used as a stream manipulator:
CAudit audit
audit << "Billy" << write;

That overload of the template for function pointers surely is too much for good old Visual Studio 6.
As a workaround you could define a type for your manipulator and overload operator<< for that type.
Here's some code:
#include "stdafx.h"
#include <string>
#include <iostream>
#include <sstream>
#include <windows.h>
class CAudit {
std::ostringstream audittext;
void do_write() {}
public:
~CAudit() { do_write(); }
// types for manipulators
struct Twrite {};
// manipulators
static Twrite write;
// implementations of <<
template<typename T>
CAudit& operator << ( const T& data ) {
audittext << data;
return *this;
}
CAudit& operator << ( LPCSTR data ) {
audittext << data;
return *this;
}
CAudit& operator << ( Twrite& ) {
do_write();
return *this;
}
};
// static member initialization
CAudit::Twrite CAudit::write;
int main(int argc, char* argv[])
{
CAudit a;
int i = 123;
const char * s = "abc";
a << i << s << CAudit::write;
return 0;
}

The kind of error definitely looks like the kind of crashes caused by VC6's pre-previous-standard implementation of templates.
The best advice is of course to upgrade to either VC7.0, 7.1, 8.0, 9.0 or the beta of 10.
To compare that to Windows versions, it's still using Windows 98 when Me, 2000, XP, Vista and 7 are available.
Having said that, you can simplify the lookup a lot by a simple trick:
class CAudit {
template<typename T>
CAudit& operator<<(T const& t) {
this->print(t);
return *this;
}
private:
void print(int);
void print(LPCSTR);
void print(CAudit & (*func)(CAudit &));
template<typename T> print(T const&);
};
The hope here is that the first lookup of operator<< finds the single member template. The other operator<< candidates are non-members for other classes and built-ins. They should be unambiguously worse that this template. The second lookup inside your operator only needs to deal with CAudit members called print.

template<typename T>
CAudit& operator << (T data ) {
audittext << data;
return *this;
}
EDIT:
#include <iostream>
using namespace std;
class CAudit{
public:
CAudit(){}
template< typename T >
CAudit &operator<<(T arg);
CAudit &operator<<(char s);
};
template< typename T>
void oldLog(T arg){
cout << arg;
}
template< typename T >
CAudit &CAudit::operator<<(T arg){
oldLog( arg );
return *this;
}
CAudit &CAudit::operator<<(char arg){
oldLog( arg );
return *this;
}
int main(){
CAudit e;
e << "Hello";
e << 'T';
return 0;
}

The problem does not seem to be in the code snippet you posted. This program works fine:
#include "stdafx.h"
#include <string>
#include <iostream>
#include <sstream>
#include <windows.h>
class CAudit {
std::ostringstream audittext;
public:
std::string getAuditText() const { return audittext.str(); }
template<typename T>
CAudit& operator << ( const T& data ) {
audittext << data;
return *this;
}
CAudit& operator << ( int data ) {
audittext << data;
return *this;
}
CAudit& operator << ( LPCSTR data ) {
audittext << data;
return *this;
}
};
int main(int argc, char* argv[])
{
CAudit a;
int i = 123;
const char * s = "abc";
a << i;
a << s;
std::cout << "audittext is: '" << a.getAuditText() << "'\n";
return 0;
}
Could you post some more code?

Related

Passing unlimited arguments to logging function in C++17

So I have implemented a rather trivial logger but I would like to extend it so I can pass arguments of data to it, possibly with formatting and I can't seem to figure out how to best do it.
So far it is written like so:
// Standard Headers.
#include <ostream>
#include <variant>
#include <memory>
#include <utility>
#include <mutex>
#include <array>
#include <string_view>
#include <iostream>
namespace Logger {
// Various logging severity levels.
enum class Level {
Info
};
class Log {
public:
// Takes standard streams cout, cerr, etc.
explicit Log(std::ostream& p_stream) : m_log(&p_stream) {}
// Create logger using std::make_unique<std::ofstream>(...) so ownership is passed.
explicit Log(std::unique_ptr<std::ostream> p_stream) : m_log(std::move(p_stream)) {}
template <typename T>
inline void info(T&& p_message);
private:
template <typename T>
void log(T&& p_msg) const {
auto const t_lock = std::lock_guard(*m_lock);
std::visit([&](auto&& p_ptr) {
(*p_ptr) << p_msg;
}, m_log);
};
std::ostream& stream() const {
return std::visit([](auto&& ptr) -> std::ostream& {
return *ptr;
}, m_log);
}
template <typename T>
inline void add(Logger::Level p_level, T&& p_message);
std::variant<std::unique_ptr<std::ostream>, std::ostream*> m_log;
std::unique_ptr<std::mutex> m_lock = std::make_unique<std::mutex>();
std::array<std::string_view, 1> m_levels = { "Info" };
};
template <typename T>
void Log::add(Level p_level, T&& p_message) {
auto const f_lock = std::lock_guard(*m_lock);
stream() << m_levels[static_cast<size_t>(p_level)] << ": " << p_message << '\n';
}
template <typename T>
inline void Log::info(T&& p_message) {
add(Level::Info, p_message);
}
}
int main() {
auto logger = Logger::Log(std::cout);
logger.info("Hello, world!");
return 0;
}
What I would like to do is when I use .info() be able to specify any number of arguments which will be replaced when writing to the log, similar to this:
logger.info("Some error message with arg: {}", 1);
How would I go about doing this? What is the best approach?
I usually use std::any. This is a non optimized version (uses copies instead of references, removes item from vector etc) but the basic idea is to convert a compile-time parameter pack to a run time one with this line:
std::vector<std::any> a = {args ...};
You can use references with, say, std::vector<std::any> a = {std::ref(args)...};
The full function would be like that:
template<typename ... many>
void safe_printf2(const char *s, many ... args)
{
using namespace std;
vector<any> a = {args ...};
while (*s) {
if (*s == '%') {
if (*(s + 1) == '%') {
++s;
}
else {
if (a.empty())
throw logic_error("Fewer arguments provided to printf");
if (a[0].type() == typeid(string)) cout << any_cast<string>(a[0]);
if (a[0].type() == typeid(int)) cout << any_cast<int>(a[0]);
if (a[0].type() == typeid(double)) cout << any_cast<double>(a[0]);
a.erase(a.begin());
s++;
}
}
cout << *s++;
}
}
Example:
safe_printf2("Hello % how are you today? I have % eggs and your height is %","Jack"s, 32,5.7);
For some weird reasons, I do something similar this way (you will have to adapt it to your needs):
inline
std::ostream &
txt(std::ostream &output,
const char *format)
{
return output << format;
}
template<typename First,
typename ...Args>
inline
std::ostream &
txt(std::ostream &output,
const char *format,
First &&first,
Args &&...args)
{
while(*format)
{
if(*format=='%')
{
return txt(output << std::forward<First>(first),
++format, std::forward<Args>(args)...);
}
output << *format++;
}
return output;
}
The two previous functions use the marker % in a format string to inject the next argument (whatever it is, a value, a format specifier, a custom object...) in the stream.
Of course some adapters could ease the usage:
template<typename ...Args>
inline
std::string
txt(const char *format,
Args &&...args)
{
std::ostringstream output;
txt(output, format, std::forward<Args>(args)...);
return output.str();
}
For example:
std::ostream &
operator<<(std::ostream &output,
const MyStuff &ms)
{
return output << '[' << ms.member1 << '|' << ms.member2 << ']';
}
...
MyStuff my_stuff= ... ;
auto msg=txt("an integer %, a (formatted) real %% and something else %\n",
12, std::setprecision(12), 34.56, my_stuff);
Then it should be possible to adjust Log::add() (then Log::info() and anything related) to make it usable in a way similar to what was expected in the question
logger.info("Some error message with arg: %", 1);
Hope that helps.

Automatic template type deduction confusing pointers and references

Whilst trying to debug some code, I created a class to dump the values of a complicated hierarchy of objects to a text file so that I can compare a case where it works against a case where it doesn't. I implemented the class like this (reduced to a bare example):
#include <iostream>
class someOtherClass
{
public:
someOtherClass()
: a(0)
, b(1.0f)
, c(2.0)
{}
int a;
float b;
double c;
};
class logger
{
public:
// Specific case for handling a complex object
logger& operator << ( const someOtherClass& rObject )
{
std::cout << rObject.a << std::endl;
std::cout << rObject.b << std::endl;
std::cout << rObject.c << std::endl;
return *this;
}
// [other class specific implementations]
// Template for handling pointers which might be null
template< typename _T >
logger& operator << ( const _T* pBar )
{
if ( pBar )
{
std::cout << "Pointer handled:" << std::endl;
return *this << *pBar;
}
else
std::cout << "null" << std::endl;
return *this;
}
// Template for handling simple types.
template< typename _T >
logger& operator << ( const _T& rBar )
{
std::cout << "Reference: " << rBar << std::endl;
return *this;
}
};
int main(int argc, char* argv[])
{
logger l;
someOtherClass soc;
someOtherClass* pSoc = &soc;
l << soc;
l << pSoc;
pSoc = nullptr;
l << pSoc;
return 0;
}
I was expecting to get the following output:
0
1
2
Pointer handled:
0
1
2
null
But what I actually get is:
0
1
2
Reference: 010AF7E4
Reference: 00000000
The automatic type deduction appears to be picking the reference implementation and setting the type to someOtherClass* rather than picking the pointer implementation. I'm using Visual Studio 2012.
In logger& operator << ( const _T& rBar ) type T can be a pointer type, so in order to work properly this template needs some restriction:
template< typename _T , typename = typename ::std::enable_if_t<!std::is_pointer<_T>::value> >
logger& operator << ( const _T& rBar )
{
std::cout << "Reference: " << rBar << std::endl;
return *this;
}
Online compiler
This is required because when templates are instantiated the const _T & pBar with _T = someOtherClass * variant will be proffered as conversion sequence required in this case will only include a reference binding which is considered an identity conversion while const _T* pBar variant with _T = someOtherClass will involve a copy-initialization.
Here are a few modifications and annotations which may help as this logging class grows and becomes more mature.
I have attempted to:
a) solve the initial problem of incorrect type deduction.
b) decouple the logger from the things being logged (otherwise your logger has to know about the entire application and all libraries).
c) provide a mechanism for easily allowing logging of any type, even if provided by a third-party library.
#include <iostream>
// I've put the logger and its helpers into a namespace. This will keep code tidy and help with
// ADL.
namespace logging
{
// define a general function which writes a value to a stream in "log format".
// you can specialise this for specific types in std:: if you wish here
template<class T>
void to_log(std::ostream& os, T const& value)
{
os << value;
}
// define a general function objects for writing a log-representation of tyoe T.
// There are 2 ways to customise this.
// a) provide a free function called to_log in the same namespace as your classes (preferred)
// b) specialise this class.
template<class T>
struct log_operation
{
void operator()(std::ostream& os, T const& value) const
{
to_log(os, value);
}
};
// specialise for any pointer
template<class T>
struct log_operation<T*>
{
void operator()(std::ostream& os, T* ptr) const
{
if (!ptr)
os << "null";
else
{
os << "->";
auto op = log_operation<std::decay_t<T>>();
op(os, *ptr);
}
}
};
// the logger is now written in terms of log_operation()
// it knows nothing of your application's types
class logger
{
public:
// Template for handling any type.
// not that this will also catch pointers.
// we will disambiguate in the log_operation
template< typename T >
logger& operator << ( const T& rBar )
{
auto op = log_operation<std::decay_t<T>>();
op(std::cout, rBar);
std::cout << std::endl;
return *this;
}
};
}
class someOtherClass
{
public:
someOtherClass()
: a(0)
, b(1.0f)
, c(2.0)
{}
int a;
float b;
double c;
};
// someOtherClass's maintainer provides a to_log function
void to_log(std::ostream& os, someOtherClass const& c)
{
os << "someOtherClass { " << c.a << ", " << c.b << ", " << c.c << " }";
}
namespace third_party
{
// the is in a 3rd party library. There is no to_log function and we can't write one which will be found with
// ADL...
struct classWhichKnowsNothingOfLogs {};
}
/// ..so we'll specialise in the logging namespace
namespace logging
{
template<>
struct log_operation<::third_party::classWhichKnowsNothingOfLogs>
{
void operator()(std::ostream& os, ::third_party::classWhichKnowsNothingOfLogs const& value) const
{
os << "classWhichKnowsNothingOfLogs {}";
}
};
}
int main(int argc, char* argv[])
{
logging::logger l;
someOtherClass soc;
someOtherClass* pSoc = &soc;
l << soc;
l << pSoc;
pSoc = nullptr;
l << pSoc;
l << third_party::classWhichKnowsNothingOfLogs();
return 0;
}
expected output:
someOtherClass { 0, 1, 2 }
->someOtherClass { 0, 1, 2 }
null
classWhichKnowsNothingOfLogs {}

operator << overloading in a constructor

I'm debugging a program and I would like to make printing from that pattern:
std::cout << firstVar << ", " << secondVar << ", " << thirdVar << endl ;
shorter, i.e, the same thing should happen if we will write the code:
shortPrint(std::cout) << firstVar << secondVar << thirdVar;
note: there is no limit for the variables quantity, it can be 1 and it can be 20, so that should also work:
shortPrint(std::cout) << firstVar << secondVar << thirdVar << anotherVar << oneMoreVar;
Someone told me that the easiest wat to do that is to create class that is called "shortPrint".
Can anyone help me figuring this out?
For start, I would say that I only need to implement a constructor and operator << overloading, but I'm not sure how to do that exactly in that case.
Yes create a shortPrint class with an appropriate overloaded operator. Something like this :
class shortPrint {
ostream &o;
public:
shortPrint(ostream &o) : o(o) {}
template <typename T> shortPrint &operator<<(const T &t) {
o << t << ',';
return *this;
}
// support for endl, which is not a value but a function (stream->stream)
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
o << pf;
return *this;
}
};
That should work (basically).
To eliminate the problem of extra commas use this :
class shortPrint {
class shortPrint2{
shortPrint &s;
public:
shortPrint2(shortPrint &s) : s(s) {}
template <typename T> shortPrint2 &operator<<(const T &t) {
s.o << ',' << t ;
return *this;
}
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
s.o << pf;
return s;
}
};
ostream &o;
shortPrint2 s2;
public:
shortPrint(ostream &o) : o(o), s2(*this) {}
template <typename T> shortPrint2 &operator<<(const T &t) {
o << t;
return s2;
}
shortPrint &operator<<(ostream& (*pf)(std::ostream&)) {
o << pf;
return *this;
}
};
You can do something like the following:
class _ostream_wrap
{
public:
template <class T>
_ostream_wrap& operator << (const T & v)
{
m_ost << "[ " << v << " ]";
return (*this);
}
explicit _ostream_wrap(std::ostream & ost)
:m_ost(ost)
{}
private:
std::ostream& m_ost;
};
template <class OSTREAM>
_ostream_wrap shortPrint(OSTREAM & o)
{
return _ostream_wrap(o);
}
//...
shortPrint(std::cout) << 1 << 2;
however this implementation will not work on rvalues:
//you can't do something like the following:
shortPrint(MyOstream(some_args)) << 1;
This is because the class _ostream_wrap keeps a reference to the stream and for rvalues case it needs to make a copy. To make a copy you need to have two implementations (this would be the final version):
template <class OSTREAM>
class _ostream_wrap
{
public:
template <class T>
_ostream_wrap<OSTREAM>& operator << (const T & v)
{
m_ost << "[ " << v << " ]";
return (*this);
}
public:
//the constructor is harder to write so i decided
//that for this i will keep the member public
OSTREAM m_ost;
};
template <class OSTREAM>
_ostream_wrap<OSTREAM&> shortPrint(OSTREAM & o)
{
_ostream_wrap<OSTREAM&> rvalue;
rvalue.m_ost = o;
return rvalue;
}
template <class OSTREAM>
_ostream_wrap<OSTREAM> shortPrint(const OSTREAM & o)
{
_ostream_wrap<OSTREAM> rvalue;
rvalue.m_ost = o;
return rvalue;
}
Here's something with very basic functionality:
#include <iostream>
struct shortPrint {
explicit shortPrint(std::ostream& os)
: strm(&os), first(true) {}
template<typename T>
shortPrint& operator<<(T&& t)
{
if (first) {
first = false;
} else {
*strm << ", ";
}
*strm << std::forward<T>(t);
return *this;
}
shortPrint& operator<<( std::ostream& (*func)(std::ostream&) )
{
*strm << func;
return *this;
}
private:
std::ostream* strm;
bool first;
};
int main()
{
int i = 3;
shortPrint(std::cout) << "1" << 2 << i << std::endl;
shortPrint(std::cout) << 4;
}
The tricky part is getting the commas to be printed correctly. I chose to print them before every streamed object, except before the very first one. As you can see, there's one general operator<< template that simply prints the comma and forwards the argument. The next problem are stream manipulators, because we don't want to print commas before them. The other operator<< overload takes care of that. If you want to be more generic, there's two more you need to take care of (see no. 9 here ).
Hope that helps.
Return the ostream from the function. Something like:
std::ostream &shortPrint(std::ostream &out) {
//whatever you need here
return out;
}
Edit: you the kind of formatting you need, you need to make a class with overloaded stream operator that returns the class. But you need to keep the reference to the needed stream in the class.

invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'ostream')

I'm trying to do
cout << Print(cout); However, there is an "invalid operands to binary expression ('ostream' (aka 'basic_ostream') and 'ostream')" error when compiling.
#include <iostream>
using namespace std;
ostream& Print(ostream& out) {
out << "Hello World!";
return out;
}
int main() {
cout << Print(cout);
return 0;
}
Why this doesn't work?
How can I fix this? Thanks!!
The syntax you might be looking for is std::cout << Print << " and hello again!\n";. The function pointer is treated as a manipulator. A built-in operator << takes the pointer to Print and calls it with cout.
#include <iostream>
using namespace std;
ostream& Print(ostream& out) {
out << "Hello World!";
return out;
}
int main() {
cout << Print << " and hello again!\n";
return 0;
}
Here is your second request:
#include <iostream>
#include <vector>
#include <iterator>
template <class Argument>
class manipulator
{
private:
typedef std::ostream& (*Function)(std::ostream&, Argument);
public:
manipulator(Function f, Argument _arg)
: callback(f), arg(_arg)
{ }
void do_op(std::ostream& str) const
{
callback(str, arg);
}
private:
Function callback;
Argument arg;
};
template <class T>
class do_print : public manipulator<const std::vector<T>&>
{
public:
do_print(const std::vector<T>& v)
: manipulator<const std::vector<T>&>(call, v) { }
private:
static std::ostream& call(std::ostream& os, const std::vector<T>& v)
{
os << "{ ";
std::copy(v.begin(), v.end(),
std::ostream_iterator<T>(std::cout, ", "));
return os << "}";
}
};
template <class Argument>
std::ostream& operator<<(std::ostream& os, const manipulator<Argument>& m)
{
if (!os.good())
return os;
m.do_op(os);
return os;
}
template<class T>
do_print<T> Print(const std::vector<T>& v)
{
return do_print<T>(v);
}
int main()
{
std::vector<int> v{1, 2, 3};
std::cout << Print(v);
}

How to write a function wrapper for cout that allows for expressive syntax?

I'd like to wrap std::cout for formatting, like so:
mycout([what type?] x, [optional args]) {
... // do some formatting on x first
std::cout << x;
}
and still be able to use expressive syntax like
mycout("test" << i << endl << somevar, indent)
instead of being forced to be more verbose like
mycout(std::stringstream("test") << i ...)
How can I implement this? What type to make x?
Edit: added consideration for optional arguments
How about this:
struct MyCout {};
extern MyCout myCout;
template <typename T>
MyCout& operator<< (MyCout &s, const T &x) {
//format x as you please
std::cout << x;
return s;
}
And put MyCout myCout; into any one .cpp file.
You can then use myCout like this:
myCout << "test" << x << std::endl;
And it will call the template operator<< which can do the formatting.
Of course, you can also provide overloads of the operator for special formatting of specific types if you want to.
EDIT
Apparently (thanks to #soon), for standard manipulators to work, a few more overloads are necessary:
MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ostream &)) {
f(std::cout);
return s;
}
MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ios &)) {
f(std::cout);
return s;
}
MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ios_base &)) {
f(std::cout);
return s;
}
EDIT 2
I may have misunderstoor your original requirements slightly. How about this (plus the same manipulator overloads as above):
struct MyCout
{
std::stringstream s;
template <typename T>
MyCout& operator << (const T &x) {
s << x;
return *this;
}
~MyCout() {
somehow_format(s);
std::cout << s.str();
}
};
int main() {
double y = 1.5;
MyCout() << "test" << y;
}
This comes easy with variadic template arguments:
template <class T>
void print(T t)
{
std::cout << t;
}
template <class T, class... Args>
void print(T t, Args... args)
{
std::cout << t << std::endl;
print(args...);
}
int main()
{
std::cout << std::boolalpha;
print(3, 's', true, false);
}
Output:
3
s
true
false
Live Demo
A variation from the answers:
#include <iostream>
using namespace std;
class MyCout
{
public:
MyCout& operator()(bool indent) {
if ( indent ) cout << '\t';
return *this;
}
template<class T>
MyCout& operator<<(T t) {
cout << t;
return *this;
}
MyCout& operator<<(ostream& (*f)(ostream& o)) {
cout << f;
return *this;
};
};
int main()
{
MyCout mycout;
int x = 10;
mycout(true)<< "test" << 2 << x << endl ;
}
You can use this kind of class:
#include <iostream>
using namespace std;
class CustomOut
{
public:
template<class T>
CustomOut& operator<<(const T& obj)
{
cout << " my-cout " << obj;
return *this;
}
};
int main()
{
CustomOut mycout;
mycout << "test" << 4 << "\n" << 3.4;
}
You'd need more code to use std::endl and other functors, so i've used here simple \n instead.