1

We have just noticed that our code doesn't compile with gcc, but didn't have any issue with clang. We normally write getters without a get prefix because it often looks nicer, such as Context().Route().Leg(1).Arcs().

It can be made to work in gcc by specifying -fpermissive, but what does that mean for standard-conformance?

class Contained {};
class Aggregate {
    Contained contained_;
public:
    class Contained Contained() { return contained_; }
    //              ^~~~~~~~~ gcc: error, declaration changes meaning; clang: ok
};

https://godbolt.org/z/n96bsoaYc

Felix Dombek
  • 13,664
  • 17
  • 79
  • 131
  • 1
    You can change this code to become legal by fully qualifying the type name: https://godbolt.org/z/74r8EP8hb I'd recommend choosing different names instead though. Btw: why be inconsistent with the use of `class` with the `Contained` type. – fabian Dec 22 '22 at 14:20
  • I think this is more of a language lawyer question than a "how do I make it work consistently"? I'm struggling to find any reasonable answer, and if authors of two major compilers disagree I'd be inclined to guess the Standard is ambiguous. – BoBTFish Dec 22 '22 at 14:23
  • See dupe: [C++ odd compile error: error: changes meaning of "Object" from class "Object"](https://stackoverflow.com/questions/282800/c-odd-compile-error-error-changes-meaning-of-object-from-class-object) – Jason Dec 22 '22 at 14:24
  • "*We normally write getters without a get prefix*" Nobody's making you use a prefix, but seeing `NameOfType()` should mean that you just created an object, not called a function. – Nicol Bolas Dec 22 '22 at 14:28
  • Note that this also holds for free functions: `Contained Contained() {return {};}`. It's not special to member-functions: gcc rejects it, clang accepts it. – bitmask Dec 22 '22 at 14:33
  • a namespace might help? https://godbolt.org/z/3qh4q11b9 – Alan Birtles Dec 22 '22 at 14:36
  • *We normally write getters without a `get` prefix...* I approve, that's what I do as well. I also name the getter after the member variable, not after the member variable's type. And my user-defined types start (like yours) with an uppercase. My member variables that are exposed with getters/setters have a leading underscore, and are all snake-case. `Contained contained() const { return _contained; }` I use a trailing underscore for parameter names to de-collision them. – Eljay Dec 22 '22 at 15:08
  • To make GCC happy, inside Aggregate you can use `::Contained`. I'm not sure if GCC is correct to be grumpy about this code *as is*, or if Clang is correct to be happy about this code. You might want to add `language-lawyer` tag to this question. – Eljay Dec 22 '22 at 15:15
  • 1
    Note that on the first line, `Contained contained_;` `Contained` refers to the injected-class-name but on the last line you hide the injected-class-name. You need to change the first line to also be `class Contained contained_;`. The rule being violated is discussed here: https://stackoverflow.com/q/23773504 (But it is "ill formed, no diagnostic required") – Artyer Dec 24 '22 at 18:55

0 Answers0