Is there a Perl script to implement C++ Class get/

2019-04-11 00:44发布

问题:

I was reading this morning the book The Pragmatic Programmer Chapter 3 on Basic Tools every programmer should have and they mentioned Code Generation Tools. They mentioned one Perl script for C++ programs which helped automate the process of implementing the get/set() member functions for private data members.

Does anyone know about such a script and where to find it? I've been unable to come up with the right google keywords to find it.

回答1:

Although it doesn't directly answer your question, you may find that generated code is actually unnecessary for managing properties in C++. The following template code will allow you to declare and use properties conveniently:

// 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

Here is the code:

// 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() is a function that tests whether the value being assigned is valid. You can override it in a subclass:

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!";
        }
    }
};

There you have it -- all of the advantages of externally-generated getter/setter functions, with none of the mess! :)

You could choose to have check() return a bool indicating validity instead of throwing an exception. And you could in principle add a similar method, access(), for catching read references to the property.

EDIT: As Mr. Fooz notes in the comments, the class author can later change the implementation without modifying the logical structure of the class (e.g. by replacing the property<int> x member with a pair of x() methods), although binary compatibility is lost so users will need to recompile their client code whenever such a change is made. This ability to painlessly incorporate future changes is actually the main reason people use getter/setter functions instead of public members in the first place.

Performance note: Because we are using the CRTP to achieve "compile-time polymorphism", there is no virtual-call overhead for providing your own check() in a subclass, and you need not declare it virtual.



回答2:

As most C++ private members should not be accesible via Get/Set style functions, this seems like a bad idea.

For a simple example of why this is so, consider the C++ std::string class. Its private members probably look something like this (exact implementation not important):

private:
   int last, len;
   char * data;

Do you believe it makes any sense to provide get/set members for those?



回答3:

I can't help you with the location of that particular script. However, there are quite a lot of code generation tools. You may even have what you are looking for already part of your IDE. For more debate/input on how, why, and whether to use code generation tools, you might look at this stackoverflow question. I like the accepted answer on that question.



回答4:

You want a script to generate get/set functions for all of your private members indiscriminately? That wouldn't be a very useful script; you probably no going to find it in Google. If you want to be able to somehow tag your member variable and have getter and/or setter skeletons automatically generated for you, than a IDE macro seems more appropriate. Try Google for that.



回答5:

I know of one programmer who uses Perl to augment the C preprocessor when it comes to macros (latest version of that project). The basic idea is you would decide on some convention to tell your Perl script when to generate a getter or setter:

struct My_struct {
    //set
    //get
    int x;

    int y;

    //get
    int z;
};

Given code like this, I could write a script to look for comment lines consisting of the comment "get" or "set" on the line(s) before a member variable declaration, and then replace them with simple setters/getters. In the above example I would generate void set_x(int i), int get_x(), and int get_z() after the associated member variable definitions.

A word of warning: do not do this in-place with s///. Instead, scan each line individually, and if you find an appropriate comment line push something that says "I need a getter/setter" onto a stack, then when you see the associated member variable, pop things off of the stack and generate the code.

There are a few devils in the details, but overall that is the idea.