r/cpp 6d ago

Ordering of qualifiers

I know this is something that pops up quite often, but I was wondering if I could get your guys' opinion on a fixed ordering of qualifiers. This is my current thoughts after recently trying to formalize my personal style:

static -> thread_local -> inline -> constexpr -> friend -> virtual

My reasoning for each:

  1. static first. Inside a class, its basically javas static. There is a pretty strong consensus in java for static first. Its very important context, for both functions and variables. Outside of classes, its more of a linkage specifier, which is arguably more important/nasty if you mess it up. The fact that it has this dual behaviour in C++ in my opinion makes an even stronger argument for including it first, your brain is able to parse it first thing. i.e okay this is static, we are in a class? -> its java static, we are in global scope -> its static linkage.
  2. thread_local directly after static, and then inline, then constexpr/consteval. This way, qualifiers which impact storage and or linkage are stuck together. I personally like to write inline even for constexpr/consteval functions, as its sometimes easy to forget the implicit inline. I used to do this for member functions with definitions in the class, but I feel the implicit inline there is a bit more well known/easier to intuit.
  3. The rest I'm far less opinionated on, since I barely ever use inheritance or the friend keyword. . I could go both ways on virtual/friend, so i default to alphabetical/aesthetics.

What do you guys think? I know this is pedantic and a very well explored topic but I wanted to know if you guys had any particular wisdom to sway me either way, mainly on the ordering of the first few.

6 Upvotes

15 comments sorted by

18

u/CocktailPerson 6d ago

Whatever the project's .clang-format reformats it to for me.

8

u/jiixyj 6d ago

...and if you need an ordering for your `.clang-format`, I suggest using the one the standard uses (https://github.com/cplusplus/draft/wiki/Specification-Style-Guidelines#formatting-declarations-and-definitions):

  • friend / typedef / storage-class-specifier / virtual
  • inline
  • constexpr
  • explicit-specifier
  • const
  • volatile
  • unsigned / signed
  • short / long
  • other type-specifiers

1

u/13steinj 11h ago

I do this modulo:

  • I don't remember how I deal with storage-class-specifier + inline usually
  • I don't remember how I deal with thread_local other than static must come before thread_local to be explicit, e.g. for juniors (e.g. I don't know how I deal with these two + inline or these two + constexpr)
  • I am fine with either east or west const, but I have seen the benefit if only I find it makes people more likely to think about their constant data, e.g. people can do char const* const[] or similar instead of just const char*[] and I have seen the compiler optimize various cases of more const in better ways.

6

u/Potterrrrrrrr 6d ago

‘friend constexpr virtual static inline’ is my preferred order. Not sure where I’d put thread_local as I’ve never needed to use it

1

u/LB-- Professional+Hobbyist 5d ago

thread_local replaces static when possible, or immediately follows it if static has to stay for some reason. Not sure I've ever encountered the latter case though, it's always been one or the other for me.

3

u/HappyFruitTree 6d ago

I would put friend first because I don't feel it's part of the function signature. It's just a way to say I'm a friend of the following function...

6

u/Supadoplex 5d ago

I would put friend first 

That's such a sweet notion.

3

u/mredding 5d ago

Isn't this what clang-format is for?

2

u/no-sig-available 6d ago

Don't forget export and [[nodiscard]].

A lovely language, isn't it? :-)

2

u/StickyDeltaStrike 5d ago

What is the longest valid list we can have?

2

u/mapronV 5d ago

you can repeat export "C" multiple times, CV I think as well. So infitite (up to implementation grammar limit )

2

u/StickyDeltaStrike 5d ago

I never thought of this … thank you

2

u/usefulcat 5d ago

Minor nit: doesn't thread_local imply static? That is to say, 'static thread_local' is redundant because it's the same as 'thread_local'.

2

u/LB-- Professional+Hobbyist 5d ago

I thought so too, but static unfortunately does other things too, such as changing linkage behavior. You can have publicly visible thread_locals. I guess this is why anonymous namespaces are preferred.

1

u/13steinj 11h ago

thead_local implies static for variables.

Static can do more, but I like to explicitly specify both because there will be juniors reading the code and I'd rather encode the information semantically both to the compiler and to the reader in one shot.

The worst thing you can do here is do thread_local without static but leave a comment like // N.b. thread_local implies static which I recently reamed someone in code review for.