【发布时间】:2010-10-23 15:55:10
【问题描述】:
今天早上我正在阅读 The Pragmatic Programmer 第 3 章关于每个程序员都应该拥有的基本工具的书,其中提到了代码生成工具。 他们提到了一个用于 C++ 程序的 Perl 脚本,该脚本有助于自动化实现私有数据成员的 get/set() 成员函数的过程。
有谁知道这样的脚本以及在哪里可以找到它?我一直无法想出正确的谷歌关键字来找到它。
【问题讨论】:
标签: c++ perl code-generation
今天早上我正在阅读 The Pragmatic Programmer 第 3 章关于每个程序员都应该拥有的基本工具的书,其中提到了代码生成工具。 他们提到了一个用于 C++ 程序的 Perl 脚本,该脚本有助于自动化实现私有数据成员的 get/set() 成员函数的过程。
有谁知道这样的脚本以及在哪里可以找到它?我一直无法想出正确的谷歌关键字来找到它。
【问题讨论】:
标签: c++ perl code-generation
虽然它没有直接回答您的问题,但您可能会发现生成的代码实际上对于管理 C++ 中的属性是不必要的。下面的模板代码可以让你方便的声明和使用属性:
// Declare your class containing a few properties
class my_class {
public:
property<int> x;
property<string> y;
...
};
...
my_class obj;
cout << obj.x(); // Get
obj.y("Hello, world!"); // Set
代码如下:
// Utility template to choose the 2nd type if the 1st is void
template <typename T, typename U>
struct replace_void {
typedef T type;
};
template <typename T>
struct replace_void<void, T> {
typedef T type;
};
// Getter/setter template
template <typename T, typename D = void>
class property {
typedef typename replace_void<D, property>::type derived_type;
derived_type& derived() { return static_cast<derived_type&>(*this); }
public:
property() {} // May be safer to omit the default ctor
explicit property(T const& v) : _v(v) {}
property(property const& p) : _v(p._v) {}
property& operator=(property const& p) { _v = p._v; return *this; }
T operator()() const { return _v; } // Getter
void operator()(T const& v) { derived().check(v); _v = v; } // Setter
protected:
// Default no-op check (derive to override)
void check(T const& v) const { (void)v; //avoid unused variable warning}
private:
T _v;
};
check() 是一个测试分配的值是否有效的函数。您可以在子类中覆盖它:
class nonnegative_int : public property<int, nonnegative_int> {
public:
// Have to redeclare all relevant ctors unfortunately :(
nonnegative_int(int v) : property<int, nonnegative_int>(v) {}
void check(int const& v) const {
if (v < 0) {
throw "Yikes! A negative integer!";
}
}
};
你有它 - 外部生成的 getter/setter 函数的所有优点,没有任何混乱! :)
您可以选择让check() 返回一个bool 来指示有效性,而不是抛出异常。原则上,您可以添加一个类似的方法 access() 来捕获对该属性的读取引用。
编辑: 正如 Fooz 先生在 cmets 中指出的那样,类作者稍后可以在不修改类的逻辑结构的情况下更改实现(例如,将 property<int> x 成员替换为一对x() 方法),尽管丢失了二进制兼容性,因此无论何时进行此类更改,用户都需要重新编译其客户端代码。 这种轻松整合未来变化的能力实际上是人们首先使用 getter/setter 函数而不是公共成员的主要原因。
性能说明:因为我们使用CRTP 来实现“编译时多态性”,所以在子类中提供您自己的check() 没有虚拟调用开销,并且您不需要声明它virtual。
【讨论】:
由于大多数 C++ 私有成员不应通过 Get/Set 样式函数访问,这似乎是个坏主意。
关于为什么会这样的简单示例,请考虑 C++ std::string 类。它的私有成员可能看起来像这样(确切的实现并不重要):
private:
int last, len;
char * data;
您认为为它们提供 get/set 成员是否有意义?
【讨论】:
我无法帮助您确定该特定脚本的位置。但是,有quite a lot 的代码生成工具。您甚至可能已经将您正在寻找的东西作为 IDE 的一部分。有关如何、为什么以及是否使用代码生成工具的更多辩论/意见,您可以查看this stackoverflow question。我喜欢这个问题的公认答案。
【讨论】:
您想要一个脚本不加选择地为所有您的私人成员生成 get/set 函数吗?那不是一个非常有用的脚本;您可能不会在 Google 中找到它。如果您希望能够以某种方式标记您的成员变量并为您自动生成 getter 和/或 setter 骨架,那么 IDE 宏似乎更合适。试试谷歌吧。
【讨论】:
我知道一位程序员 uses Perl to augment the C preprocessor 谈到宏 (latest version of that project)。基本思想是您将决定一些约定来告诉您的 Perl 脚本何时生成 getter 或 setter:
struct My_struct {
//set
//get
int x;
int y;
//get
int z;
};
给定这样的代码,我可以编写一个脚本来在成员变量声明之前的行中查找由注释“get”或“set”组成的注释行,然后用简单的 setter/getter 替换它们.在上面的示例中,我将在关联的成员变量定义之后生成 void set_x(int i)、int get_x() 和 int get_z()。
警告:不要在原地使用 s/// 执行此操作。相反,单独扫描每一行,如果你找到合适的注释行,将“我需要一个 getter/setter”的内容推送到堆栈上,然后当你看到相关的成员变量时,将内容从堆栈中弹出并生成代码.
细节上有些小问题,但总的来说就是这样。
【讨论】: