c++c++17constantsclang++nodiscard

Implicit [[nodiscard]] for all const-tagged methods?


I'd like to update my library's API so that the compiler warns whenever the user calls a const-tagged method and then ignores the method's return value. The reasoning is that since a const method has no side effects, the only reason to call it would be to examine its return-value... so if the programmer doesn't do so, that's almost certainly an error, and the programmer's attention should be called to it. (and in the very rare case where the programmer really did mean to do that, he should add a (void) tag to the call to make his unusual decision explicit)

C++17's [[nodiscard]] attribute provides just that behavior, but adding [[nodiscard]] to every single one of thousands of const-tagged methods is tedious and (worse) clutters up the header files with lots of noise; it would be nicer if there was some compiler-flag I could use to tell my compiler that any const-tagged method should also be considered [[nodiscard]] by default.

Does such a compiler-flag exist? FWIW I use primarily clang++, but also sometimes g++ and MSVC.

FWIW I tried -Wunused-result, but that didn't seem to make any difference in the compiler's behavior.

Usage example below:

class MyContainer
{
public:
   MyContainer() : _count(0) {/* empty */}

   // This works but it would be better if `const` implied `[[nodiscard]]`
   [[nodiscard]] bool IsEmpty() const {return (_count == 0);}

private:
   int _count;
};

int main(int argc, char ** argv)
{
   MyContainer c;
   c.IsEmpty();  // should generate a warning, because the user didnt' use the result, so calling the const-method makes no sense
   return 0;
}

Solution

  • The answer to my question appears to be "no, such a feature does not exist" -- probably for the reasons described by the commenters above; namely, because a const-tagged method can still have side effects outside of its class-object (e.g. it can do I/O, it can modify static/global variables, it can modify variables that were passed in as by-reference or by-pointer arguments, it can modify mutable member-variables, etc).

    Specifically, a const tag doesn't guarantee that the method is "pure".

    Given that, I spent the last couple of days going through all the header files in my library and manually adding [[nodiscard]] where it seemed appropriate; of the 337 const-tagged methods in my library, only 4 of them made sense to call without examining the return value. It would therefore have been nice of C++ (and C before it) had made [[nodiscard]] the default behavior and instead had a [[maydiscard]] attribute that allowed a function to opt-out of the discard-warnings; but that decision was made decades ago and backwards compatibility concerns prevent it from being changed now, so it seems there is nothing that can be done about that.