我想知道以下语法是否可以被“承认”,或者好的做法是否认为这是来自地狱。目标是增加一定程度的保护,迫使开发人员充分意识到他在做什么。这是语法:
class MyClass
{
public:
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return _writeStream;
}
inline const std::ofstream& writeStream() const
{
return _writeStream;
}
protected:
std::ofstream _writeStream;
};
使用方法是:
x.writeStream().good(); // <- OK
x.writeStream().put('c'); // <- NOT OK
x.writeStream<true>().put('c'); // <- OK
我发现这是告诉开发人员的一种方便方式:“小心,你正在使用低级功能,你必须小心你正在做的事情”。它是一种“可接受的”方式,通过一种“保护”来直接接触集体成员吗?还有其他编码方式吗?
答案 0 :(得分:2)
你使你的代码变得丑陋,难以维护和不方便......究竟是什么?定义您的界面。这是你班级的接口。不要让开发人员通过使用一些荒谬的模板标记hackery来绕过它。如果你正在编写代码,你总是要知道你在做什么。必须明确键入
<true>
以表明您特别知道自己在做什么只是......非常非常错误。开发人员有文档。他们不需要训练轮和人工限制,他们需要清晰简洁的代码,让他们完成任务。 - meagar 2012-10-06 02:41:53Z
当其他用户使用它时,您提供给其他人的类永远不能进入不可预测的状态。在这种情况下,一个不可预测的状态是您在编写课程时从未考虑过的状态。因此,您应该永远不允许访问到您的类的低级方法或记录可能的缺陷。
让我们说你正在写一个记录器:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
private:
std::ofstream stream;
};
忽略没有复制构造函数,并且缺少赋值操作数。还要忽略它是一个粗略的记录器,它甚至不提供时间戳。但是,正如您所看到的,记录器的状态完全取决于记录器的方法,例如,如果文件已成功打开,则在记录器被销毁之前不会关闭。
现在说我们使用你的方法:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return stream;
}
inline const std::ofstream& writeStream() const
{
return stream;
}
private:
std::ofstream stream;
};
现在有人使用以下代码
logger.writeStream<true>.close();
邦。你的记录器坏了。当然这是用户的错,因为他们使用了<true>
,不是吗?但是,用户通常会复制示例代码,特别是如果他第一次使用库。用户会看到您的示例
logger.writeStream().good(); // <- OK
logger.writeStream().put('c'); // <- NOT OK
logger.writeStream<true>().put('c'); // <- OK
首先完全忽略文档。然后他将使用第一个和最后一个版本。后来他发现最后一个版本每次都! <true>
是多么神奇的事情。然后他开始责怪你发生的邪恶事件,所以你要保护自己免受明显的火焰,并提供包含警告的文件:
/**
* \brief Returns a reference to the internal write stream
*
* \note You have to use the template parameter `<true>` in order to use it
*
* \warning Please note that this will return a reference to the internal
* write stream. As such you shouldn't create any state in which
* the logger cannot work, such as closing the stream.
*/
template<bool RemoveProtection = false>
inline std::ofstream& writeStream()
{
static_assert(RemoveProtection, "You're doing it wrong");
return stream;
}
那么,我们得到了什么?我们仍然不得不在某处发出警告。如果我们将stream
公开:
struct MyLogger{
MyLogger(std::string filename) : stream(filename.c_str()){}
template <typename T>
MyLogger& operator<<(const T& v){ stream << v << " "; return *this;}
/**
* The internal write stream. Please look out that you don't create
* any state in which the logger cannot work, such as closing the stream.
*/
std::ofstream stream;
};
或坚持
/** >put warning here< */
inline std::ofstream & writeStream()
{
return stream;
}
Woops。因此要么不允许访问您的低级方法(如果应该允许它们使用它们,请构建特定std::ofstream
方法的包装器),或者记录如果将对象的内部结构更改为可能发生的可能缺陷,但不要走中间路线,并使static_assert
看起来没问题。