0

We have a legacy C++ DB application, which I'll just oversimplify here: Over a dozen very wide DB tables represent partly similar kinds of data, so there is some overlap in the columns. The schema changes only slightly every few months, but the interface to it is dynamic, where table_name.column_name is looked up and represented by an ID. When we deal with the data in memory, it is all in a list, with each field having its ID associated.

This works well, but addressing data is messy. We have a lookup function for IDs based on a string (get_ID( type_A1, "title" )), and where we have code dealing with a specific type, colleagues tend to write the IDs literally. I would want to generate symbolic names corresponding to the string, so that much of this can be looked up at compile time. My naive idea went like:

struct ANY {
    virtual const int
        title, aaa, bbb, ccc, ddd; // ...
}

struct A1 : ANY {
    const int
        title=17, aaa=29, bbb=5, ddd=27;
}

struct B1 : ANY {
    const int
        title=71, aaa=92, ccc=45;
}

And usage would be either direct A1::bbb or B1::aaa where we know which type we are dealing with or:

const ANY& any = determine_type();
int title_id = any.title;

Alas C++ allows none of this, only methods can be virtual. :-( One solution might be wrapping them in methods:

struct ANY {
    virtual int get_title() const = 0;
    virtual int get_aaa() const = 0;
}

struct B1 : ANY {
    const int
        title=71, aaa=92, ccc=45;
    int get_title() const { return title; };
    int get_aaa() const { return aaa; };
}

For thousands of consts this approach feels so wrong! Another solution might be doing the dynamic part via an indirect name and lookup function:

enum names { title_name, aaa_name, bbb_name, ccc_name };

struct ANY {
    virtual int get( names ) const = 0;
}

struct B1 : ANY {
    const int
        title=71, aaa=92, ccc=45;
    static const int[] my_consts = { title, aaa, -1, ccc }; // pseudo code
    int get( names n ) const { return my_consts[n]; };
}

This means having all identifiers in two variants – ugly! Does anybody have a clean, intuitive and space efficient solution?

Daniel
  • 521
  • 1
  • 4
  • 13
  • The method approach seems the correct one to me. Thousands of consts "feel so wrong" anyway, no matter if you dress them in ()'s or not. – Daniel Daranas Sep 12 '13 at 10:18

1 Answers1

1

An enum might be the better idea.

enum fields { title, aaa, bbb, ccc };

struct ANY {
  virtual int get(field f);
}; 

struct A1 : public ANY {
  virtual int get(field f) {
    switch (f) {
      case title : return 71;
      //
    }
  }
}; 
MSalters
  • 173,980
  • 10
  • 155
  • 350
  • I'm liking this more and more. Especially by making the method const, the compiler should optimize it away in `a1.get( title )` given `const A1 a1`. One worry I have is that enums can be assigned to int, so someone might accidentally use that instead of getting the real number. What would be the best way to give `title` a type that only works as parameter to `get` while being usable in `switch`? – Daniel Sep 13 '13 at 09:48
  • @Daniel: See http://stackoverflow.com/questions/6936030/do-we-really-need-enum-class-in-c11 – MSalters Sep 13 '13 at 10:30
  • thanks! Alas we must still deploy to old machines where C++11 is not an option :-( – Daniel Sep 13 '13 at 10:56
  • Well, that's a clear message to communicate: "We have a solution which works, but due to the age of the machines is unsafe". Let the Powers That Be decide what they find important. – MSalters Sep 13 '13 at 11:01
  • I have since found a major drawback to this solution: I had verified that, given a const parameter, the optimizer turns the method result into a compile time constant. Alas that's not enough to make it a "constant expression" so it is not usable in many places (like case labels). – Daniel Oct 12 '13 at 11:29
  • That's inherent to any solution which uses a virtual call (since that's RTTI, **run time** type information), and you can't avoid that if you want `const ANY& any = determine_type();` at runtime. Worse, you're apparently double-dispatching: once to get a constant, once in a switch. – MSalters Oct 13 '13 at 22:47