相关代码是:
std::fstream fout("Logs.txt");
class Logs;
typedef std::ostream& (*ostream_manipulator2)(std::ostream&);
class LogsOutput
{
public:
LogsOutput() {}
~LogsOutput() {}
Logs * pLogs;
friend LogsOutput& operator<<(LogsOutput &logsClass, std::string &strArg);
friend LogsOutput& operator<<(LogsOutput &logsClass, const char *strArg);
friend LogsOutput& operator<<(LogsOutput &logsClass, ostream_manipulator2 pf);
friend LogsOutput& operator<<(LogsOutput &logsClass, uint64_t number);
};
LogsOutput *pLogsOutput;
template <typename T>
T& LOUToutput()
{
if (pLogsOutput)
{
return (*pLogsOutput);
}
else
return fout;
}
我想这样称呼这个函数:
LOUToutput () << "Print this line " << std::endl;
但有时会创建LogsOutput
类,因此取消引用其指针会崩溃,在这种情况下我宁愿输出到文件。
我知道编译器在编译时无法告诉LogsOutput
类是否会被实例化,因此不能推断出模板的类型,但我没有看到任何其他方法可以使它工作。
所以我的问题是我的函数如何根据运行时条件返回不同的类型?
答案 0 :(得分:2)
对此的复杂解决方案是使用继承。如果你要从std :: ostream继承,你可以返回一个公共基类(如果你感兴趣的话,这是一个讨论:How to inherit from std::ostream?)
更简单的解决方案是,返回一个代理类,根据需要重定向输出。
struct LogProxy {
LogsOutput *pLog;
// ...
LogProxy &operator<<(std::string &o) {
if(pLogsOutput) {
*pLog << o;
} else {
// Assuming this is available as a global.. You probably don't want to do that
fout << o;
}
return *this;
}
// ....
};
LogProxy LOUToutput() {
return LogProxy { pLogsOutput; };
}
其他一些一般性意见:
如果您想使用模板,则需要将其设置为编译时条件。你可以使用像std :: enable_if&lt;&gt;这样的东西。提供LOUToutput()的多个模板重载,在编译时选择登录的位置。
我猜这只是为了发布到SO,但是你的代码在头文件中声明了多个全局变量。你需要解决这个问题。
您的代码没有const声明。很多这些运算符看起来至少应该在它们的输出(字符串,.etc。)参数上声明为const。
编辑:这是一个有效的(正确编译)样本:
#include <iostream>
struct PRXY {
bool cond;
const PRXY &operator<<(const std::string &t) const {
if(cond) {
std::cout << t;
} else {
std::cerr << t;
}
return *this;
}
};
PRXY pr(bool cond) {
return PRXY { cond };
}
void test() {
pr(false) << "Hello";
}