Answer to the Question
There is no standard compiler flag that warns when a struct is written without an explicit private: or protected: section. The most reliable way to enforce explicit access labels across a codebase is to combine a style rule, a static‑analysis check (e.g. clang‑tidy or cppcheck), and a pre‑commit hook that blocks code violating the rule.
Why the Flag Gap Exists
Compilers treat struct and class as syntactically equivalent except for the default access level. The language standard does not expose this default as a diagnostic, and existing warning lists focus on initialization or visibility violations that already occur when code attempts to access a member that is not public.
Practical Enforcement Steps
- Define a style rule: "All
struct definitions must begin with an explicit private: or protected: section, unless the struct is intentionally a plain‑data holder.">
- Choose a linter: Use
clang‑tidy with a custom check or an existing one that flags structs lacking an access specifier. If no built‑in check exists, write a small clang‑tidy plugin that reports a diagnostic for a StructDecl node without an AccessSpecDecl before the first non‑static member.
- Integrate into CI: Add the linter to the build pipeline. Treat the diagnostic as an error (e.g.
-Werror or a custom error flag) so that the CI fails on violations.
- Pre‑commit hook: Run the linter locally before commits. A simple
git commit -n hook can invoke the linter and reject the commit if the rule is broken.
- Code‑review checklist: Include a mandatory check for explicit access specifiers in the review template.
Optional: Use class Instead of struct
Because class defaults to private, switching to class for types that should not expose data members is a quick way to avoid accidental public access. This changes the public API, so use it only when refactoring is acceptable.
Verification Test
#include <iostream>
struct Foo {
int a; // implicitly public
};
int main() {
Foo f;
f.a = 5; // OK – public member
std::cout << f.a << std::endl;
}
// Compile with clang++ -Wall -Werror
// The program compiles fine. If Foo is changed to:
// struct Foo { private: int a; }; // then f.a is a compile‑time error.
Follow‑Up Question
Do you need this rule to apply to all struct definitions in the project, or only to those in specific namespaces or modules?