views:

88

answers:

2

I'm designing a public API in C++ and believe I'd like to retain C++ property-function style conventions that look like int& Value(), and const int& Value() const as opposed to get/set prefixes which return/assign by value because I feel the usage patterns are more concise and equally readable, while blending into existing C++ code very easily.

I need to allow the programmer to supply his own metadata, I've chosen to do so by exposing a void* property function. The problem is of course that having signatures like

class foo {
  int& Value();
  const int& Value() const;
  void* Metadata()  
  void* const Metadata() const
};

doesn't work because the following won't compile:

 void* ptr = ...;
 foo.Metadata() = ptr;

Because of this, I would have to use something like the following to make it work:

class foo {
  int& Value();
  const int& Value() const;
  void* GetMetadata();
  void SetMetadata(void* const data);
};

But that would render the styles inconsistent, so for now I've opted to stick with get/set prefixes throughout the entire API because of that, eg:

class foo {
  int GetValue() const;
  void SetValue(int value);
  void* GetMetadata() const;
  void SetMetadata(void* const data);
};

Of course, that doesn't fit the language convention I'd like to use, is there an alternative approach to this whole thing? If so, what is it? Am I stuck with get/set prefixes?

Note: I can't replace void* with templates for user meta-data as the ABI should be as stable as possible.

Also, I have already supplied a string get/set pair typed unsigned char* for user strings.

After some careful (re)consideration I've opted to stick with get/set prefixes, I also won't use references for void* - if void* gives off a smell, void*& is pretty much a public landfill. As such, I've essentially opted for something similar to this:

typedef void* Any;

class foo {
  ...
  Any GetObject() const;
  void SetObject(Any);
  ...
};

Thanks for your input. :)

+3  A: 

Not that I'm sure this is the best design but, sticking to the question: If, for an attribute of type "int", you write:

int& Value(); //Used as setter
int Value()const; //Used as getter

do the same for an attribute of type "void*":

void*& Meta(); //Used as setter
void* Meta()const; //Used as getter
Éric Malenfant
What part of the design don't you like?
Geoff
Probably the part about it being a `void*`. Generally, that's a bit of code smell.
greyfade
Indeed, and I agree, but sometimes you just have to make trade-offs (see added notes at the bottom of my question).
Geoff
+2  A: 

You could have your Metadata functions return references to pointers:

class foo {
  int& Value();
  const int& Value() const;
  void*& Metadata()  
  const void* const & Metadata() const
};

Another alternative is to use overloading:

class foo{
  int Value() const;
  void Value(int);
  void* Metadata() const;
  void Metatdata(void*);
};

If you go this route, you could also make the setters return the old value for convenience.

coppro
I guess you must be using an old compiler that doesn't support that - it works fine here.
coppro
seems I deleted my comment after you saw it, heh. At any rate; I'm using MSVC 2008, and the api will be cross-platform (gcc). what were the function definitions of your first foo class? I copy-pasted yours as an exercise and failed to get it to compile.
Geoff
though replacing void* with a typedef does get your first example to compile (excluding the redundant const in the second Metadata declaration, /W4).
Geoff
coppro