6

Context

I'm working on a large project combined from different modules. We've got a exporter with a template function export<T>(const T& obj) which works only on POD types (it does static_assert for is_pod if you're curious). Currently I'm sitting on the part of the system that's responsible for cataloging some entities (their type is irrelevant) that are described by metadata. The metadata itself is returned by some function called metadata describe(const entity& obj), and should be immutable after returning. Of course the function itself sets the metadata members inside its body.

Problem

Due to the facts mentioned above, I need to design a const POD type. Since POD types cannot have user-defined constructors, the member variables themselves cannot be const. Also returning a const variable by value directly from describe is meaningless (or not very helpful to say the least).

Attemted solutions

So basically what I've thought of so far is:

  • overload exporter.export<T>(...) for metadata, but that's not really a solution since it solves only the problem with the current class, while in the final product there will be many types of entities (And I'm not talking about . Overloading the function for all the types seems just wrong.
  • design an immutable wrapper and return it from describe. That's what I'm currently doing, since I can't figure out a better way to solve the problem. The wrapper offers an implicit conversion to const &T and stores a T inside of itself, thus it can be passed directly to the export function.

Question

Is there a better way to return an immutable POD class from a function? Am I missing something? For simplicity reasons lets assume metadata is defined as follows:

struct metadata{
    int parameter1;
    time_t parameter2;
};

and describe works as follows (currently, skipping the current solution):

metadata describe(const entity& obj){
   metadata m;
   m.parameter1 = obj.param1();
   m.parameter2 = obj.param2();
   return m;
}
Community
  • 1
  • 1
Paweł Stawarz
  • 3,952
  • 2
  • 17
  • 26
  • 1
    The function shouldn't care if its return data is mutable or not, as it's by value and has no link to the function after it's executed. If caller wants to store it in a const variable, it is more than welcome to. – Neil Kirk Jul 27 '14 at 23:38
  • 1
    @NeilKirk since we're talking about __metadata__ (so data describing other data), it would be peculiar if the user could modify it and then pass it to the `exporter`, since he would just export false information to the database. The only way the metadata could change is when the data it describes changes, and that's not really for the user to monitor. – Paweł Stawarz Jul 27 '14 at 23:42
  • Is this for security or preventing accidental changes? Why not make the members of metadata private and provide only const getters. – Neil Kirk Jul 27 '14 at 23:45
  • 1
    @NeilKirk That would not be a POD anymore. Actually, the requirement to have a POD limits the solutions space quite heavily... – Daniel Frey Jul 27 '14 at 23:46
  • 1
    @DanielFrey True. I wonder where the requirement for a POD comes from. Is exporter doing something dodgy? Well you can have a non-POD version for the user to get, which is converted to a POD version inside exporter. – Neil Kirk Jul 27 '14 at 23:48
  • @PawełStawarz, your comment about user modifying metadata before passing it to `exporter::export` indicates that metadata needs to be an opaque pointer that a user cannot muck with. Otherwise, there are legal ways to construct a different metadata object before passing it to `exporter::export`. – R Sahu Jul 27 '14 at 23:57
  • 1
    @RSahu if the user decides to screw himself, that's not really something we care about. However - blessed with the knowledge from various other projects - we tend to acknowledge the average user doesn't read the documentation and tends to make unintentional mistakes. The more we can protect him from that possibility, the better, since instead of answering not-so-bright questions multiple times, we can focus on more important things. With a given monthly budget - less helpers hired == more programmers hired. – Paweł Stawarz Jul 28 '14 at 00:03

1 Answers1

7

You can make the member variables const, you just need to initialize the object with an initializer list:

struct metadata{
    const int parameter1;
    const time_t parameter2;
};

and

metadata describe(const entity& obj){
   return { obj.param1(), obj.param2() };
}
Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • Maybe there is some case the metadata isn't immutable. I find it's better to have a const object with non-const members, than the other way round. – Neil Kirk Jul 27 '14 at 23:39
  • I agree with the comment, it would be best if it was the other way round. Still - I'm upvoting this answer since it's far better than returning a wrapped instance, and - probably - it's the best solution there is. Gonna wait a bit more before accepting tho. – Paweł Stawarz Jul 27 '14 at 23:44
  • 2
    @PawełStawarz Given that it has to be a POD, you can't do much about it. You could of course return `const metadata` in addition to making the members `const` (just to document your intent that the user should *really* not change it), but since it's a POD the user can always create one with `metadata m{ 42, 1764 }` and use that instead. You can prevent accidents, but you can't protect yourself against malicious users. – Daniel Frey Jul 27 '14 at 23:54
  • Returning const metadata won't help as it can just be returned to a non-const variable directly. – Neil Kirk Jul 27 '14 at 23:56
  • +1 `You can prevent accidents, but you can't protect yourself against malicious users` – Neil Kirk Jul 27 '14 at 23:57
  • @Jarod42 GCC 4.8.1 says it's a POD. – Paweł Stawarz Jul 28 '14 at 02:22
  • 1
    @Jarod42 Strange. Clang [accepts it](http://coliru.stacked-crooked.com/a/99c9d6fed0a8b106) and §3.9/9 and §9 allow cv-qualified members IIUC. Do you have any standard reference which would make a struct non-POD because of a `const` member? – Daniel Frey Jul 28 '14 at 07:22
  • I trusted my version of gcc. so it should be a bug. (or maybe one version of the definition of pod disallows it and an other allows it...) – Jarod42 Jul 28 '14 at 07:32
  • @PawełStawarz: GCC 4.9.0 says it's not http://coliru.stacked-crooked.com/a/f9aa41bfd2e7a985. Standard seems to imply it should be POD thought – Mooing Duck Jul 28 '14 at 21:24
  • @MooingDuck that's peculiar. We wanted to switch to 4.9.0 after this project, but now I'm not sure if that's a good idea. Clearly there's no reason for a struct with `const` members __not__ being a POD (both in terms of logic _and_ the Standard). – Paweł Stawarz Jul 28 '14 at 21:37
  • @MooingDuck: I think it must be a GCC bug. `std::is_pod::value` is true. And a struct composed of POD should also be POD. But GCC says it isn't. The struct with const int also fails `is_trivial` on GCC. – Zan Lynx Jul 28 '14 at 22:26
  • @ZanLynx: The only thing I can think of is that such a struct would have no implicit copy/move assignment, it's the only thing I can think of that would have any relevance at all. – Mooing Duck Jul 28 '14 at 22:43