编译器无法推断出哪种模板类型 return
Compiler cannot deduce which template type to return
相关代码是:
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
class 不会创建,因此取消引用其指针会崩溃,在这种情况下我宁愿输出到文件。
我知道编译器无法在编译时判断 LogsOutput
class 是否会被实例化,因此无法推断出模板的类型,但我看不出有任何其他方法可以做到工作。
所以我的问题是我的函数 return 如何根据 运行 时间条件成为不同的类型?
对此的复杂解决方案是使用继承。如果你要从 std::ostream 继承,你可以 return 一个共同的基础 class (如果你有兴趣,这里是一个讨论:How to inherit from std::ostream?)
在我看来,更简单的解决方案是 return 一个代理 class,根据需要重定向输出。
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<> 之类的东西来提供 LOUToutput() 的多个模板重载,这些模板在 编译 时间选择要登录的位置。
我猜这只是为了发布到 SO,但是您的代码在头文件中声明了多个全局变量。你需要解决这个问题。
您的代码中没有 const 声明。许多这些运算符看起来至少应该在其输出(字符串等)参数上声明为 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";
}
相关代码是:
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
class 不会创建,因此取消引用其指针会崩溃,在这种情况下我宁愿输出到文件。
我知道编译器无法在编译时判断 LogsOutput
class 是否会被实例化,因此无法推断出模板的类型,但我看不出有任何其他方法可以做到工作。
所以我的问题是我的函数 return 如何根据 运行 时间条件成为不同的类型?
对此的复杂解决方案是使用继承。如果你要从 std::ostream 继承,你可以 return 一个共同的基础 class (如果你有兴趣,这里是一个讨论:How to inherit from std::ostream?)
在我看来,更简单的解决方案是 return 一个代理 class,根据需要重定向输出。
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<> 之类的东西来提供 LOUToutput() 的多个模板重载,这些模板在 编译 时间选择要登录的位置。
我猜这只是为了发布到 SO,但是您的代码在头文件中声明了多个全局变量。你需要解决这个问题。
您的代码中没有 const 声明。许多这些运算符看起来至少应该在其输出(字符串等)参数上声明为 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";
}