C++ [[nodiscard]] on Class and Enum Declarations

This article explains how the [[nodiscard]] attribute behaves when applied directly to class, struct, or enumeration types in C++. Introduced in C++17 and expanded in C++20, this feature allows developers to enforce call-site handling of specific types across an entire codebase. You will learn the mechanics of type-level application, how it differs from function-level annotations, common use cases, and how to suppress warnings when necessary.

How Type-Level [[nodiscard]] Operates

When the [[nodiscard]] attribute is applied to the declaration of a class, struct, or enum, its warning behavior automatically propagates to any function that returns that type by value. Rather than annotating every individual function that returns a critical type, declaring the type itself as [[nodiscard]] guarantees that the compiler warns developers whenever an instance returned by value is discarded.

struct [[nodiscard]] ErrorCode {
    int code;
};

ErrorCode processData() {
    return ErrorCode{0};
}

int main() {
    processData(); // Compiler warning: return value of type 'ErrorCode' declared with 'nodiscard' attribute discarded
    
    ErrorCode err = processData(); // OK: return value is consumed
    return 0;
}

Application to Enumerations

Applying [[nodiscard]] to an enumeration is particularly useful for status indicators, error codes, and operational results. Any function that returns the annotated enumeration by value triggers a compiler diagnostic if the caller ignores the result.

enum class [[nodiscard]] Status {
    Success,
    Failure,
    Pending
};

Status checkStatus();

void run() {
    checkStatus(); // Compiler warning: ignoring return value
}

By-Value vs. References and Pointers

The standard specifies that [[nodiscard]] applied to a type only takes effect when a function returns that type by value. If a function returns a reference (T&, const T&) or a pointer (T*) to a [[nodiscard]] class or enumeration, the compiler will not emit a warning if the return value is discarded.

struct [[nodiscard]] Resource {};

Resource createResource(); // Warns if discarded
Resource& getGlobalResource(); // Does NOT warn if discarded
Resource* findResource(); // Does NOT warn if discarded

C++20 String Literals

Starting in C++20, [[nodiscard]] can include a string literal to provide an explicit explanation for why the returned type must not be ignored.

class [[nodiscard("Discarding this object results in an immediate resource leak.")]] ScopedLock {
    // RAII lock implementation
};

When a caller ignores a returned ScopedLock, the compiler displays the custom message alongside the warning.

Suppressing the Warning

If an operation returns a [[nodiscard]] type and you intentionally want to ignore the result, you can explicitly cast the function call to void. This signals intent to both the compiler and future maintainers, suppressing the warning cleanly:

(void)processData(); // OK: Explicitly discarded, no warning emitted