【发布时间】:2019-04-18 18:25:54
【问题描述】:
与Error "Unterminated conditional directive" in cross-referencing headers相关
我有一个可序列化的模板类:
serializable.h
#pragma once
#ifndef SERIALIZABLE_H
#define SERIALIZABLE_H
#include "Logger.h"
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception_ptr.hpp>
template<class T>
class Serializable {
public:
static bool Deserialize(Serializable<T>* object, std::string serializedObject) {
try {
return object->SetValuesFromPropertyTree(GetPropertyTreeFromJsonString(serialized));
} catch (...) {
std::string message = boost::current_exception_diagnostic_information();
Logger::PostLogMessageSimple(LogMessage::ERROR, message);
std::cerr << message << std::endl;
}
}
private:
static boost::property_tree::ptree GetPropertyTreeFromJsonString(const std::string & jsonStr) {
std::istringstream iss(jsonStr);
boost::property_tree::ptree pt;
boost::property_tree::read_json(iss, pt);
return pt;
}
}
#endif // SERIALIZABLE_H
但问题是 Logger 类使用了一个从 Serializable 继承的 LogMessage 对象(使用 CRTP)。
Logger.h
#pragma once
#ifndef LOGGER_H
#define LOGGER_H
#include "LogMessage.h"
class Logger {
public:
static void PostLogMessageSimple(LogMessage::Severity severity, const std::string & message);
}
#endif // LOGGER_H
LogMessage.h
#pragma once
#ifndef LOGMESSAGE_H
#define LOGMESSAGE_H
#include "serializable.h"
class LogMessage : public Serializable<LogMessage> {
public:
enum Severity {
DEBUG,
INFO,
WARN,
ERROR
};
private:
std::string m_timestamp;
std::string m_message;
friend class Serializable<LogMessage>;
virtual boost::property_tree::ptree GetNewPropertyTree() const;
virtual bool SetValuesFromPropertyTree(const boost::property_tree::ptree & pt);
}
#endif // LOGMESSAGE_H
这里的问题是这些文件中的每一个都包含另一个导致构建错误的文件。不幸的是,我不能使用上述链接问题的解决方案(将#include“Logger.h”移动到Serializable.cpp),因为Serializable是一个模板类,因此需要在头文件中定义。
我不知道如何继续。任何帮助表示赞赏!
编辑: 我也考虑过在 serializable.h 中使用 Logger 和 LogMessage 的前向声明,但是因为我在 Logger 中调用静态方法并使用 LogMessage::Severity,所以这不起作用。
【问题讨论】:
-
据我所知,你不能。只是不要这样写标题。例如将它们合并为一个。
-
合并标头会违反关注点分离,并且在大型项目(就是这样)中根本无法很好地扩展
-
写出(不在代码中)类之间的预期关系可能有助于揭示代码中不必要的依赖关系。例如:为什么
Severity枚举属于LogMessage而不是Logger?为什么Logger和LogMessage在同一个标题中?相关性:在提供的代码中(我假设已经简化),Serializable和Logger需要定义LogMessage的唯一原因是可以访问Severity枚举,这似乎是需要的弱理由类定义。 -
@JaMit,您说得对,代码已被简化以显示问题。实际上,LogMessage 和 Logger 位于不同的标头中。但是,为了不提供太多不必要的信息,我省略了。同样,Logger 严重依赖 LogMessage 的其他特性,确实需要包含它。
-
@KevinRak 我无意在 cmets 中回答,但由于我的问题可能会导致解决方案,因此我继续将一些相关想法收集到官方答案中。 (有点长。抱歉。)
标签: c++ templates circular-dependency template-classes