所以这是一个有趣的问题,我怎么能做一些像cout包装的东西? 我想能够将它添加到一个DLL中,所以我可以把它扔进我的程序。但它的基本语法应该是
Mything::mesage << "I'm some text" << im_an_int << someclass << mything::endl;
或
Mything::mesageandlog << "I'm going to print to console, and to a file!" << mything::endl;
我可以处理大部分内部逻辑,但至于我应该做什么甚至做到这一点。有点难过。
可能在我的类中创建一个名为message的静态流成员,然后在写入时通过方法运行它时会触发事件吗?
Idk,我环顾四周,找到了类似的东西,但至于把它扔进了一个dll我不知所措。 (How to write a function wrapper for cout that allows for expressive syntax?) 因为这需要我使用extern和变量,但是如何让它静态,所以我可以直接调用它而不创建变量?
有点澄清,如下: mydll.h
#include <iostream>
namespace mynamespace {
extern struct LogMessage{};
template <typename T>
LogMessage& operator<< (LogMessage &s, const T &x) {
SetStdHandle(STD_OUTPUT_HANDLE, GetStdHandle(STD_OUTPUT_HANDLE));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE);
std::cout << "[IF] ";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_WHITE);
//LogTimestamp(); --ill impliment this.
std::cout << x << endl;
//writeStreamToLogfile(s); --and ill handle this.
return s;
}
}
driverprogram.h
#include <mydll.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
mynamespace::LogMessage << "Something: << std::endl;
}
预期产出:
"[IF] [00:00:00] Something
答案 0 :(得分:3)
您可以创建一个结构,其中包含&lt;&lt;操作
struct OutputThing
{
template< class T >
OutputThing &operator<<( T val )
{
std::cout<<val;
return *this;
}
};
现在,无论何时想要记录,都必须实例化对象。
OutputThing()<<"x ="<<x;
如果您想避免重复构造和破坏对象,可以将其设为单例。
struct OutputThingSingleton
{
static OutputThingSingleton& GetThing()
{
static OutputThingSingleton OutputThing;
return OutputThing;
}
template< class T >
OutputThingSingleton &operator<<( T val )
{
std::cout<<val;
return *this;
}
private:
OutputThingSingleton()
{};
};
所以电话现在看起来像
OutputThingSingleton::GetThing()<<"x ="<<x;
您可以使用宏缩短。
这将适用于多个dll,但是根据它的使用方式,您可以拥有单个实例的多个实例。只要你不想在你的单身人士中维持任何状态,这就可以正常工作。如果确实需要确保单个实例,可以在自己的dll中编译它。使用此dll的任何其他二进制文件将共享由dll“拥有”的单个实例。
答案 1 :(得分:2)
首先,为了给出公平的警告,我很确定这在DLL中不起作用。你想把它放在标题中(如这里所示)。
其次,它可能比您考虑的更精细。特别是,它定义了一个多输出流类,其工作方式与任何其他流类似。基本上任何operator<<
的正常重载都可以正常工作。
与普通流运算符不同,输出转到多个流,和每行输出(在所有流上)前面都有一个前缀(当前设置为值“[FIX] ]“,但它只是使用字符串的内容,所以你在该字符串中放置的任何内容都应该有用。更精细/完成的实现可能允许你设置类似操纵器的前缀,但是这个(当前)没有支持那个。
最后,它会执行一些可变参数模板技巧,因此您可以将输出文件指定为文件名或现有ostream对象,或其组合(例如,请参见演示文稿main
)。
首先,标题:
#ifndef LOGGER_H_INC_
#define LOGGER_H_INC_
#include <iostream>
#include <streambuf>
#include <vector>
#include <fstream>
class logger: public std::streambuf {
public:
logger(std::streambuf* s): sbuf(s) {}
~logger() { overflow('\n'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if (traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch (c) {
case '\n':
case '\r': {
prefix = "[FIX]";
buffer += c;
if (buffer.size() > 1)
sbuf->sputn(prefix.c_str(), prefix.size());
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
buffer.clear();
return rc;
}
default:
buffer += c;
return c;
}
}
std::string prefix;
std::streambuf* sbuf;
string buffer;
};
namespace multi {
class buf : public std::streambuf {
std::vector<std::streambuf *> buffers;
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
buf() {}
void attach(std::streambuf *s) { buffers.push_back(s); }
void attach(std::ofstream &s) { buffers.push_back(s.rdbuf()); }
int_type overflow(int_type c) {
bool eof = false;
for (std::streambuf *buf : buffers)
eof |= (buf->sputc(c) == traits_type::eof());
return eof ? traits_type::eof() : c;
}
};
class logstream : public std::ostream {
std::vector<std::ofstream *> streams;
buf outputs;
logger log;
void attach(std::ostream &s) { outputs.attach(s.rdbuf()); }
void attach(char const *name) {
std::ofstream *s = new std::ofstream(name);
streams.push_back(s);
outputs.attach(s->rdbuf());
}
template <typename T, typename...pack>
void attach(T &t, pack&...p) {
attach(t);
attach(p...);
}
public:
template <typename...pack>
logstream(pack&...p) : log(&outputs), std::ostream(&log) { attach(p...); }
~logstream() {
for (auto d : streams) {
d->close();
// Bug: crashes with g++ if delete is allowed to execute.
//delete d;
}
}
};
}
#endif
然后是如何使用它的演示:
#include "logger"
int main(){
multi::logstream l(std::cout, "c:/path/log.txt");
l << "This is a prefixed string\n";
}
显然标题相当大,但是使用它的代码似乎(至少对我来说)就像你希望的那样简单 - 创建一个对象,指定你想要输出的位置,只是一个普通的流 - 除了您可以指定多个。然后像对待任何其他流一样写入它,输出转到所有指定的输出,每行前面都有指定的前缀。